diff --git a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-api.md b/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-api.md deleted file mode 100644 index 00c59e3d5..000000000 --- a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-api.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@tauri-apps/api": minor:feat ---- - -Adds the `scrollBarStyle` option to the Webview and WebviewBuilder constructors. diff --git a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-config.md b/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-config.md deleted file mode 100644 index 0d8b8dcfa..000000000 --- a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri-config.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": minor:feat -"tauri-utils": minor:feat ---- - -Adds the `scrollBarStyle` option to the window configuration. diff --git a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri.md b/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri.md deleted file mode 100644 index 9d604375c..000000000 --- a/.changes/14089-expose-scrollbarstyle-webview-option-to-tauri.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"tauri-runtime-wry": minor:feat -"tauri-runtime": minor:feat -"tauri": minor:feat ---- - -Adds the `scroll_bar_style` option to the Webview and WebviewWindow builders. -The possible values for this option are gated behind conditional compilation -flags, and will need to be applied using conditional compilation if customised. diff --git a/.changes/CHANGES.md b/.changes/CHANGES.md deleted file mode 100644 index 132f1aa2e..000000000 --- a/.changes/CHANGES.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'tauri-cli': 'minor:feat' -'tauri-bundler': 'minor:feat' ---- - -Add a `--no-sign` flag to the `tauri build` and `tauri bundle` commands to skip the code signing step, improving the developer experience for local testing and development without requiring code signing keys. diff --git a/.changes/adaptive_icons.md b/.changes/adaptive_icons.md deleted file mode 100644 index cee66fe93..000000000 --- a/.changes/adaptive_icons.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'tauri-cli': 'patch:enhance' ---- - -Add support for Android's adaptive and themed icons. 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/android-init-windows-unix.md b/.changes/android-init-windows-unix.md deleted file mode 100644 index e188ee5bd..000000000 --- a/.changes/android-init-windows-unix.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'tauri-cli': 'patch:bug' -'@tauri-apps/cli': patch:bug ---- - -Strip Windows-only extensions from the binary path so an Android project initialized on Windows can be used on UNIX systems. diff --git a/.changes/android-plugin-bool-is-deserialize.md b/.changes/android-plugin-bool-is-deserialize.md deleted file mode 100644 index bf4eceac5..000000000 --- a/.changes/android-plugin-bool-is-deserialize.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": patch:bug ---- - -Properly deserialize Android plugin args with key starting with `is` (previously treated as a getter instead of a field name). diff --git a/.changes/check-mismatched-versions-tauri-info.md b/.changes/change-pr-13253.md similarity index 62% rename from .changes/check-mismatched-versions-tauri-info.md rename to .changes/change-pr-13253.md index 88bf5f190..e42a66072 100644 --- a/.changes/check-mismatched-versions-tauri-info.md +++ b/.changes/change-pr-13253.md @@ -1,6 +1,6 @@ --- -"tauri-cli": patch:enhance "@tauri-apps/cli": patch:enhance +"tauri-cli": patch:enhance --- -Check mismatched versions in `tauri info` +Allow electron to run the CLI directly diff --git a/.changes/change-pr-14632.md b/.changes/change-pr-14632.md new file mode 100644 index 000000000..068994f0d --- /dev/null +++ b/.changes/change-pr-14632.md @@ -0,0 +1,7 @@ +--- +"tauri-utils": patch:enhance +"tauri-build": patch:enhance +"tauri-cli": patch:enhance +--- + +Small code refactors for improved code readability. No user facing changes. diff --git a/.changes/change-pr-14766.md b/.changes/change-pr-14766.md new file mode 100644 index 000000000..4fb885f88 --- /dev/null +++ b/.changes/change-pr-14766.md @@ -0,0 +1,5 @@ +--- +"tauri-macos-sign": patch:deps +--- + +Remove once-cell-regex from direct dependencies. 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/config.json b/.changes/config.json index a4ca328f7..97a6917b8 100644 --- a/.changes/config.json +++ b/.changes/config.json @@ -27,12 +27,6 @@ "dryRunCommand": true, "pipe": true }, - { - "command": "cargo generate-lockfile", - "dryRunCommand": true, - "runFromRoot": true, - "pipe": true - }, { "command": "cargo audit ${ process.env.CARGO_AUDIT_OPTIONS || '' }", "dryRunCommand": true, diff --git a/.changes/data-dir-js.md b/.changes/data-dir-js.md deleted file mode 100644 index 9fff3317d..000000000 --- a/.changes/data-dir-js.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-utils": "minor:enhance" -"@tauri-apps/api": "minor:enhance" ---- - -Added a config to set a data_directory relative to the app-specific data dir in JavaScript and `tauri.conf.json`. diff --git a/.changes/default-log-level.md b/.changes/default-log-level.md deleted file mode 100644 index 7b3f0ca3e..000000000 --- a/.changes/default-log-level.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@tauri-apps/cli": patch:enhance -"tauri-cli": patch:enhance ---- - -Set a default log level filter when running `tauri add log`. diff --git a/.changes/empty-vec-instead-of-none.md b/.changes/empty-vec-instead-of-none.md new file mode 100644 index 000000000..6b0dd9fd9 --- /dev/null +++ b/.changes/empty-vec-instead-of-none.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": patch:enhance +"tauri-cli": patch:enhance +--- + +Simplified internal representation of `features: Option>` with `Vec`, no user facing changes diff --git a/.changes/ensure-android-env.md b/.changes/ensure-android-env.md deleted file mode 100644 index f7e13f8da..000000000 --- a/.changes/ensure-android-env.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": minor:feat -"@tauri-apps/cli": minor:feat ---- - -Try to detect ANDROID_HOME and NDK_HOME environment variables from default system locations and install them if needed using the Android Studio command line tools. diff --git a/.changes/file-association-content-type.md b/.changes/file-association-content-type.md deleted file mode 100644 index 985bbfa24..000000000 --- a/.changes/file-association-content-type.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": minor:feat -"@tauri-apps/cli": minor:feat ---- - -Added support to defining the content type of the declared file association on macOS (maps to LSItemContentTypes property). diff --git a/.changes/file-association-exported-type-cli.md b/.changes/file-association-exported-type-cli.md deleted file mode 100644 index b2685b37d..000000000 --- a/.changes/file-association-exported-type-cli.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": minor:feat -"@tauri-apps/cli": minor:feat ---- - -Added support to defining the metadata for custom types declared in `tauri.conf.json > bundle > fileAssociations > exportedType` via the `UTExportedTypeDeclarations` Info.plist property. diff --git a/.changes/file-association-exported-type.md b/.changes/file-association-exported-type.md deleted file mode 100644 index 75cf0545f..000000000 --- a/.changes/file-association-exported-type.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-utils": minor:feat ---- - -Added `FileAssociation::exported_type` and `FileAssociation::content_types` for better support to defining custom types on macOS. diff --git a/.changes/fix-android-build-nvm4w-windows.md b/.changes/fix-android-build-nvm4w-windows.md deleted file mode 100644 index bbc706cde..000000000 --- a/.changes/fix-android-build-nvm4w-windows.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'tauri-cli': 'patch:bug' -'@tauri-apps/cli': patch:bug ---- - -Enhance Android build script usage on Windows by attempting to run cmd, bat and exe formats. 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/fix-ios-cmd-pkg-name-change.md b/.changes/fix-inspect-description.md similarity index 53% rename from .changes/fix-ios-cmd-pkg-name-change.md rename to .changes/fix-inspect-description.md index 42c4eb1e7..df1c87db9 100644 --- a/.changes/fix-ios-cmd-pkg-name-change.md +++ b/.changes/fix-inspect-description.md @@ -1,6 +1,6 @@ --- -"tauri-cli": patch:bug "@tauri-apps/cli": patch:bug +"tauri-cli": patch:bug --- -Fix iOS CLI usage after modifying the package name. +Fixed the command description for `tauri inspect` diff --git a/.changes/fix-js-icon-tauri-info.md b/.changes/fix-js-icon-tauri-info.md deleted file mode 100644 index e0da44656..000000000 --- a/.changes/fix-js-icon-tauri-info.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri-cli": patch:bug -"@tauri-apps/cli": patch:bug ---- - -Replaced the non-standard nerd font character with ` ⱼₛ` in `tarui info` diff --git a/.changes/fix-unspeficied-dev-host.md b/.changes/fix-unspeficied-dev-host.md deleted file mode 100644 index 488585513..000000000 --- a/.changes/fix-unspeficied-dev-host.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@tauri-apps/cli": patch:bug -"tauri-cli": patch:bug ---- - -Resolve local IP address when `tauri.conf.json > build > devUrl` host is `0.0.0.0`. diff --git a/.changes/improve-errors.md b/.changes/improve-errors.md deleted file mode 100644 index 7a8cfe734..000000000 --- a/.changes/improve-errors.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"@tauri-apps/cli": minor:enhance -"tauri-cli": minor:enhance -"tauri-bundler": minor:enhance ---- - -Improve error messages with more context. - diff --git a/.changes/info-plist-config.md b/.changes/info-plist-config.md deleted file mode 100644 index cafab53c8..000000000 --- a/.changes/info-plist-config.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -"tauri-utils": minor:feat -"tauri-cli": minor:feat -"@tauri-apps/cli": minor:feat ---- - -Added `bundle > macOS > infoPlist` and `bundle > iOS > infoPlist` configurations to allow defining custom Info.plist extensions. - diff --git a/.changes/install-ios-platform.md b/.changes/install-ios-platform.md deleted file mode 100644 index 907f411e5..000000000 --- a/.changes/install-ios-platform.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@tauri-apps/cli": minor:enhance -"tauri-cli": minor:enhance ---- - -Prompt to install the iOS platform if it isn't installed yet. diff --git a/.changes/ios-async-support.md b/.changes/ios-async-support.md deleted file mode 100644 index cfe444e0a..000000000 --- a/.changes/ios-async-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri": minor:feat ---- - -Support async Swift plugin methods (`completionHandler:`) in PluginManager diff --git a/.changes/linux-webcontext.md b/.changes/linux-webcontext.md new file mode 100644 index 000000000..0a14638d3 --- /dev/null +++ b/.changes/linux-webcontext.md @@ -0,0 +1,5 @@ +--- +tauri-runtime-wry: patch:bug +--- + +On Linux, keep the WebContext alive to prevent zombie WebKit processes after repeatedly closing all windows and re-opening them. diff --git a/.changes/linuxdeploy-extract.md b/.changes/linuxdeploy-extract.md deleted file mode 100644 index d6dceada1..000000000 --- a/.changes/linuxdeploy-extract.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -tauri-bundler: patch:bug ---- - -Set `APPIMAGE_EXTRACT_AND_RUN` on top of using the `--appimage-extra-and-run` cli arg for linuxdeploy. diff --git a/.changes/mobile-pnpm-dlx-init.md b/.changes/mobile-pnpm-dlx-init.md deleted file mode 100644 index f9a0f3925..000000000 --- a/.changes/mobile-pnpm-dlx-init.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@tauri-apps/cli": patch:bug -"tauri-cli": patch:bug ---- - -Fixes mobile project initialization when using `pnpx` or `pnpm dlx`. diff --git a/.changes/mobile-run.md b/.changes/mobile-run.md deleted file mode 100644 index 9026f2273..000000000 --- a/.changes/mobile-run.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@tauri-apps/cli": minor:feat -"tauri-cli": minor:feat ---- - -Added `ios run` and `android run` commands to run the app in production mode. 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/reduce-internal-statics.md b/.changes/reduce-internal-statics.md new file mode 100644 index 000000000..bc20780b1 --- /dev/null +++ b/.changes/reduce-internal-statics.md @@ -0,0 +1,6 @@ +--- +"@tauri-apps/cli": patch:changes +"tauri-cli": patch:changes +--- + +Refactored internal use of static on config and directory resolvings, no user facing changes, please report any regressions if you encounter any diff --git a/.changes/refactor-info-plist.md b/.changes/refactor-info-plist.md deleted file mode 100644 index 734969f27..000000000 --- a/.changes/refactor-info-plist.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": minor:breaking ---- - -Changed `MacOsSettings::info_plist_path` to `MacOsSettings::info_plist`. diff --git a/.changes/register-plugin-listener-fix.md b/.changes/register-plugin-listener-fix.md deleted file mode 100644 index e3b31cc86..000000000 --- a/.changes/register-plugin-listener-fix.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@tauri-apps/api": patch:bug ---- - -Fix `core > addPluginListener` failing on command permission check. diff --git a/.changes/runtime-bsd.md b/.changes/runtime-bsd.md new file mode 100644 index 000000000..c9c97b4c4 --- /dev/null +++ b/.changes/runtime-bsd.md @@ -0,0 +1,6 @@ +--- +tauri-runtime: patch:bug +tauri-runtime-wry: patch:bug +--- + +Fix compilation errors when targeting BSD. diff --git a/.changes/signing-env-vars.md b/.changes/signing-env-vars.md new file mode 100644 index 000000000..c164c3b9a --- /dev/null +++ b/.changes/signing-env-vars.md @@ -0,0 +1,14 @@ +--- +"tauri-cli": patch:enhance +"@tauri-apps/cli": patch:enhance +--- + +Added new environment variables for `tauri signer sign` command, to align with existing environment variables used in `tauri build`, `tauri bundle` and `tauri signer generate` +- `TAURI_SIGNING_PRIVATE_KEY` +- `TAURI_SIGNING_PRIVATE_KEY_PATH` +- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD` + +The old environment variables are deprecated and will be removed in a future release. +- `TAURI_PRIVATE_KEY` +- `TAURI_PRIVATE_KEY_PATH` +- `TAURI_PRIVATE_KEY_PASSWORD` diff --git a/.changes/stack-overflow-release-build.md b/.changes/stack-overflow-release-build.md deleted file mode 100644 index 921e614ba..000000000 --- a/.changes/stack-overflow-release-build.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"tauri": "patch:bug" -"tauri-macros": "patch:bug" ---- - -Fix the stack overflow when having too many commands in a single invoke handler in release build diff --git a/.changes/support-raw-entitlements.md b/.changes/support-raw-entitlements.md deleted file mode 100644 index a23732405..000000000 --- a/.changes/support-raw-entitlements.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"tauri-bundler": minor:feat ---- - -Support providing `plist::Value` as macOS entitlements. diff --git a/.changes/universal-app-links-macos.md b/.changes/universal-app-links-macos.md deleted file mode 100644 index 8aef107f7..000000000 --- a/.changes/universal-app-links-macos.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-cli": minor:feat -"@tauri-apps/cli": minor:feat -"tauri-utils": minor:feat ---- - -Added support to universal app links on macOS with the `plugins > deep-link > desktop > domains` configuration. diff --git a/.changes/updater-signer-files-without-extension.md b/.changes/updater-signer-files-without-extension.md new file mode 100644 index 000000000..1ff41edbd --- /dev/null +++ b/.changes/updater-signer-files-without-extension.md @@ -0,0 +1,6 @@ +--- +tauri-cli: patch:bug +"@tauri-apps/cli": patch:bug +--- + +`tauri signer sign` doesn't work for files without an extension diff --git a/.changes/warn-missing-product-name.md b/.changes/warn-missing-product-name.md deleted file mode 100644 index f2a78eae8..000000000 --- a/.changes/warn-missing-product-name.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"tauri-cli": patch:enhance -"@tauri-apps/cli": patch:enhance ---- - -Warn if productName is empty when initializing mobile project. - diff --git a/.changes/webkitgtk202.md b/.changes/webkitgtk202.md new file mode 100644 index 000000000..739ce1ebd --- /dev/null +++ b/.changes/webkitgtk202.md @@ -0,0 +1,7 @@ +--- +tauri-runtime-wry: minor:deps +tauri-runtime: minor:deps +tauri: minor:deps +--- + +**Breaking Change** for `with_webview` users: Updated webkit2gtk-rs crates to `v2.0.2`. 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/.changes/window-config-focus-default-true.md b/.changes/window-config-focus-default-true.md new file mode 100644 index 000000000..38d24aebc --- /dev/null +++ b/.changes/window-config-focus-default-true.md @@ -0,0 +1,5 @@ +--- +tauri: patch:bug +--- + +`WindowConfig::focus` is set to `false` in `WindowConfig::default()` diff --git a/.changes/wry-054.md b/.changes/wry-054.md new file mode 100644 index 000000000..9e4a0cdbe --- /dev/null +++ b/.changes/wry-054.md @@ -0,0 +1,6 @@ +--- +tauri-runtime-wry: patch:deps +tauri: patch:deps +--- + +Update wry to `v0.54`. \ No newline at end of file diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index a797449d9..f0b35f439 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -33,11 +33,9 @@ Hi! We, the maintainers, are really excited that you are interested in contribut - It's OK to have multiple small commits as you work on the PR - we will let GitHub automatically squash it before merging. - If adding new feature: - - Provide convincing reason to add this feature. Ideally you should open a suggestion issue first and have it greenlighted before working on it. - If fixing a bug: - - If you are resolving a special issue, add `(fix: #xxxx[,#xxx])` (#xxxx is the issue id) in your PR title for a better release log, e.g. `fix: update entities encoding/decoding (fix #3899)`. - Provide detailed description of the bug in the PR, or link to an issue that does. @@ -98,7 +96,7 @@ You can use `cargo install --path . --debug` to speed up test builds. You can build the Rust documentation locally running the following script: ```bash -$ RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --open +$ cargo +nightly doc --all-features --open ``` ### Developing the JS API diff --git a/.github/workflows/covector-version-or-publish.yml b/.github/workflows/covector-version-or-publish.yml index 4cebbb2e3..83ff2ddac 100644 --- a/.github/workflows/covector-version-or-publish.yml +++ b/.github/workflows/covector-version-or-publish.yml @@ -78,7 +78,6 @@ jobs: with: node-version: 20 registry-url: 'https://registry.npmjs.org' - cache: 'pnpm' - name: cargo login run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }} diff --git a/.github/workflows/publish-cli-rs.yml b/.github/workflows/publish-cli-rs.yml index a6471161c..39887eec7 100644 --- a/.github/workflows/publish-cli-rs.yml +++ b/.github/workflows/publish-cli-rs.yml @@ -38,35 +38,62 @@ jobs: rust_target: aarch64-pc-windows-msvc ext: '.exe' args: '' + - os: ubuntu-22.04 + rust_target: riscv64gc-unknown-linux-gnu + ext: '' + args: '' + cross: true steps: - uses: actions/checkout@v4 - name: 'Setup Rust' + if: ${{ !matrix.config.cross }} uses: dtolnay/rust-toolchain@stable with: targets: ${{ matrix.config.rust_target }} - uses: Swatinem/rust-cache@v2 + if: ${{ !matrix.config.cross }} with: key: ${{ matrix.config.rust_target }} - name: install Linux dependencies - if: matrix.config.os == 'ubuntu-latest' + if: ${{ !matrix.config.cross && startsWith(matrix.config.os, 'ubuntu') }} run: | sudo apt-get update sudo apt-get install -y libgtk-3-dev + - name: Install cross + if: ${{ matrix.config.cross }} + uses: taiki-e/install-action@v2 + with: + tool: cross@0.2.5 + - name: Build CLI + if: ${{ !matrix.config.cross }} run: cargo build --manifest-path ./crates/tauri-cli/Cargo.toml --profile release-size-optimized ${{ matrix.config.args }} + - name: Build CLI (cross) + if: ${{ matrix.config.cross }} + run: cross build --manifest-path ./crates/tauri-cli/Cargo.toml --target ${{ matrix.config.rust_target }} --profile release-size-optimized ${{ matrix.config.args }} + - name: Upload CLI + if: ${{ !matrix.config.cross }} uses: actions/upload-artifact@v4 with: name: cargo-tauri-${{ matrix.config.rust_target }}${{ matrix.config.ext }} path: target/release-size-optimized/cargo-tauri${{ matrix.config.ext }} if-no-files-found: error + - name: Upload CLI (cross) + if: ${{ matrix.config.cross }} + uses: actions/upload-artifact@v4 + with: + name: cargo-tauri-${{ matrix.config.rust_target }}${{ matrix.config.ext }} + path: target/${{ matrix.config.rust_target }}/release-size-optimized/cargo-tauri${{ matrix.config.ext }} + if-no-files-found: error + upload: needs: build runs-on: ubuntu-latest diff --git a/.scripts/ci/check-change-tags.js b/.scripts/ci/check-change-tags.js index 1cd7de3d9..cf6463439 100644 --- a/.scripts/ci/check-change-tags.js +++ b/.scripts/ci/check-change-tags.js @@ -57,7 +57,7 @@ function checkChangeFiles(changeFiles) { for (const [file, packages] of unknownTagsEntries) { for (const { package, tag } of packages) { console.error( - `Package \`${package}\` has an uknown change tag ${tag} in ${file} ` + `Package \`${package}\` has an unknown change tag ${tag} in ${file} ` ) } } diff --git a/.scripts/ci/check-license-header.js b/.scripts/ci/check-license-header.js index 03ad824e4..4dd48fa46 100644 --- a/.scripts/ci/check-license-header.js +++ b/.scripts/ci/check-license-header.js @@ -29,7 +29,7 @@ const ignore = [ async function checkFile(file) { if ( extensions.some((e) => file.endsWith(e)) - && !ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) == i) + && !ignore.some((i) => file.includes(`/${i}/`) || path.basename(file) === i) ) { const fileStream = fs.createReadStream(file) const rl = readline.createInterface({ 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/Cargo.lock b/Cargo.lock index 56ec5ecad..2df411247 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -300,7 +300,7 @@ dependencies = [ "ring", "rsa", "scroll", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "semver", "serde", @@ -567,7 +567,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-util", "itoa", "matchit 0.8.4", @@ -1055,9 +1055,9 @@ dependencies = [ [[package]] name = "cargo-mobile2" -version = "0.20.6" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35613119e2e16b293e56557a27da0d5bc42031f5edc0bf4f73a2b4d310d39c65" +checksum = "dcea7efeaac9f0fd9f886f43a13dde186a1e2266fe6b53a42659e4e0689570de" dependencies = [ "colored", "core-foundation 0.10.0", @@ -1083,7 +1083,7 @@ dependencies = [ "serde_json", "textwrap", "thiserror 2.0.12", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", "ureq", "which", "windows 0.61.1", @@ -1120,7 +1120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" dependencies = [ "serde", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", ] [[package]] @@ -1152,10 +1152,11 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.22" +version = "1.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32db95edf998450acc7881c932f94cd9b05c87b4b2599e8bab064753da4acfd1" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", @@ -1319,7 +1320,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" dependencies = [ "lazy_static", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -1641,6 +1642,12 @@ dependencies = [ "syn 2.0.95", ] +[[package]] +name = "ct-codecs" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b10589d1a5e400d61f9f38f12f884cfd080ff345de8f17efda36fe0e4a02aa8" + [[package]] name = "ctor" version = "0.2.9" @@ -2213,7 +2220,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", "vswhom", "winreg 0.55.0", ] @@ -2327,11 +2334,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "erased-serde" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24e2389d65ab4fab27dc2a5de7b191e1f6617d1f1c8855c0dc569c94a4cbb18d" +checksum = "89e8918065695684b2b0702da20382d5ae6065cf3327bc2d6436bd49a71ce9f3" dependencies = [ "serde", + "serde_core", "typeid", ] @@ -2462,6 +2470,12 @@ dependencies = [ "windows-sys 0.59.0", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + [[package]] name = "flate2" version = "1.1.1" @@ -2847,10 +2861,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", - "js-sys", "libc", "wasi 0.11.0+wasi-snapshot-preview1", - "wasm-bindgen", ] [[package]] @@ -2860,9 +2872,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" dependencies = [ "cfg-if", + "js-sys", "libc", "r-efi", "wasi 0.14.2+wasi-0.2.4", + "wasm-bindgen", ] [[package]] @@ -3097,7 +3111,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.7.0", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -3116,7 +3130,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.3.1", - "indexmap 2.7.0", + "indexmap 2.11.4", "slab", "tokio", "tokio-util", @@ -3169,9 +3183,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.2" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -3339,7 +3353,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", - "socket2", + "socket2 0.5.8", "tokio", "tower-service", "tracing", @@ -3348,13 +3362,14 @@ dependencies = [ [[package]] name = "hyper" -version = "1.5.2" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "256fb8d4bd6413123cc9d91832d78325c48ff41677595be797d90f42969beae0" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", + "futures-core", "h2 0.4.7", "http 1.3.1", "http-body 1.0.1", @@ -3362,6 +3377,7 @@ dependencies = [ "httpdate", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -3389,14 +3405,13 @@ checksum = "2d191583f3da1305256f22463b9bb0471acad48a4e534a5218b9963e9c1f59b2" dependencies = [ "futures-util", "http 1.3.1", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-util", - "rustls 0.23.20", + "rustls 0.23.35", "rustls-pki-types", "tokio", "tokio-rustls 0.26.1", "tower-service", - "webpki-roots 0.26.7", ] [[package]] @@ -3407,7 +3422,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-util", "native-tls", "tokio", @@ -3417,18 +3432,23 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.10" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df2dcfbe0677734ab2f3ffa7fa7bfd4706bfdc1ef393f2ee30184aed67e631b4" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ + "base64 0.22.1", "bytes", "futures-channel", + "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", - "hyper 1.5.2", + "hyper 1.8.1", + "ipnet", + "libc", + "percent-encoding", "pin-project-lite", - "socket2", + "socket2 0.6.1", "tokio", "tower-service", "tracing", @@ -3459,9 +3479,9 @@ dependencies = [ [[package]] name = "ico" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" +checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371" dependencies = [ "byteorder", "png", @@ -3714,13 +3734,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.7.0" +version = "2.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5" dependencies = [ "equivalent", - "hashbrown 0.15.2", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] @@ -3808,6 +3829,16 @@ version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" +[[package]] +name = "iri-string" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" +dependencies = [ + "memchr", + "serde", +] + [[package]] name = "is-terminal" version = "0.4.13" @@ -3907,20 +3938,6 @@ dependencies = [ "system-deps", ] -[[package]] -name = "jni" -version = "0.19.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" -dependencies = [ - "cesu8", - "combine", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", -] - [[package]] name = "jni" version = "0.21.1" @@ -3960,9 +3977,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0" [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8" dependencies = [ "once_cell", "wasm-bindgen", @@ -4068,7 +4085,7 @@ dependencies = [ "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-util", "jsonrpsee-core", "jsonrpsee-types", @@ -4131,7 +4148,6 @@ dependencies = [ "referencing", "regex", "regex-syntax", - "reqwest 0.12.12", "serde", "serde_json", "uuid-simd", @@ -4225,7 +4241,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2" dependencies = [ "cssparser", "html5ever", - "indexmap 2.7.0", + "indexmap 2.11.4", "selectors", ] @@ -4280,9 +4296,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.169" +version = "0.2.178" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" [[package]] name = "libfuzzer-sys" @@ -4311,7 +4327,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -4419,9 +4435,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.22" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" dependencies = [ "value-bag", ] @@ -4592,11 +4608,12 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "minisign" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b23ef13ff1d745b1e52397daaa247e333c607f3cff96d4df2b798dc252db974b" +checksum = "e6bf96cef396a17a96f7600281aa4da9229860b7a082601b1f6db6eaa5f99ee5" dependencies = [ - "getrandom 0.2.15", + "ct-codecs", + "getrandom 0.3.3", "rpassword", "scrypt", ] @@ -4710,10 +4727,10 @@ dependencies = [ "libc", "log", "openssl", - "openssl-probe", + "openssl-probe 0.1.5", "openssl-sys", "schannel", - "security-framework", + "security-framework 2.11.1", "security-framework-sys", "tempfile", ] @@ -4888,11 +4905,10 @@ dependencies = [ [[package]] name = "num-bigint-dig" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7" dependencies = [ - "byteorder", "lazy_static", "libm", "num-integer", @@ -5255,7 +5271,7 @@ dependencies = [ "crc32fast", "flate2", "hashbrown 0.14.5", - "indexmap 2.7.0", + "indexmap 2.11.4", "memchr", "ruzstd", ] @@ -5344,6 +5360,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +[[package]] +name = "openssl-probe" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f50d9b3dabb09ecd771ad0aa242ca6894994c130308ca3d7684634df8037391" + [[package]] name = "openssl-src" version = "300.4.1+3.4.0" @@ -6085,7 +6107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" dependencies = [ "base64 0.22.1", - "indexmap 2.7.0", + "indexmap 2.11.4", "quick-xml", "serde", "time", @@ -6347,58 +6369,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "quinn" -version = "0.11.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" -dependencies = [ - "bytes", - "pin-project-lite", - "quinn-proto", - "quinn-udp", - "rustc-hash", - "rustls 0.23.20", - "socket2", - "thiserror 2.0.12", - "tokio", - "tracing", -] - -[[package]] -name = "quinn-proto" -version = "0.11.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" -dependencies = [ - "bytes", - "getrandom 0.2.15", - "rand 0.8.5", - "ring", - "rustc-hash", - "rustls 0.23.20", - "rustls-pki-types", - "slab", - "thiserror 2.0.12", - "tinyvec", - "tracing", - "web-time", -] - -[[package]] -name = "quinn-udp" -version = "0.5.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c40286217b4ba3a71d644d752e6a0b71f13f1b6a2c5311acfcbe0c2418ed904" -dependencies = [ - "cfg_aliases", - "libc", - "once_cell", - "socket2", - "tracing", - "windows-sys 0.59.0", -] - [[package]] name = "quote" version = "1.0.38" @@ -6809,51 +6779,44 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.12" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43e734407157c3c2034e0258f5e4473ddb361b1e85f95a66690d67264d7cd1da" +checksum = "04e9018c9d814e5f30cc16a0f03271aeab3571e609612d9fe78c1aa8d11c2f62" dependencies = [ "base64 0.22.1", "bytes", - "futures-channel", "futures-core", "futures-util", "http 1.3.1", "http-body 1.0.1", "http-body-util", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-rustls 0.27.5", "hyper-tls", "hyper-util", - "ipnet", "js-sys", "log", - "mime", "native-tls", - "once_cell", "percent-encoding", "pin-project-lite", - "quinn", - "rustls 0.23.20", - "rustls-pemfile 2.2.0", + "rustls 0.23.35", "rustls-pki-types", + "rustls-platform-verifier", "serde", "serde_json", - "serde_urlencoded", "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", "tokio-rustls 0.26.1", "tokio-util", "tower 0.5.2", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 0.26.7", - "windows-registry 0.2.0", ] [[package]] @@ -6935,9 +6898,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -6953,9 +6916,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -6976,13 +6939,13 @@ checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" [[package]] name = "rpassword" -version = "7.3.1" +version = "7.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +checksum = "66d4c8b64f049c6721ec8ccec37ddfc3d641c4a7fca57e8f2a89de509c73df39" dependencies = [ "libc", "rtoolbox", - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -7017,9 +6980,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" +checksum = "b8573f03f5883dcaebdfcf4725caa1ecb9c15b2ef50c43a07b816e06799bb12d" dependencies = [ "const-oid", "digest", @@ -7159,15 +7122,15 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.20" +version = "0.23.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5065c3f250cbd332cd894be57c40fa52387247659b14a2d6041d121547903b1b" +checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" dependencies = [ "log", "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.102.8", + "rustls-webpki 0.103.8", "subtle", "zeroize", ] @@ -7178,10 +7141,10 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ - "openssl-probe", + "openssl-probe 0.1.5", "rustls-pemfile 1.0.4", "schannel", - "security-framework", + "security-framework 2.11.1", ] [[package]] @@ -7190,11 +7153,23 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" dependencies = [ - "openssl-probe", + "openssl-probe 0.1.5", "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", - "security-framework", + "security-framework 2.11.1", +] + +[[package]] +name = "rustls-native-certs" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" +dependencies = [ + "openssl-probe 0.2.0", + "rustls-pki-types", + "schannel", + "security-framework 3.5.1", ] [[package]] @@ -7217,32 +7192,32 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.10.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2bf47e6ff922db3825eb750c4e2ff784c6ff8fb9e13046ef6a1d1c5401b0b37" +checksum = "21e6f2ab2928ca4291b86736a8bd920a277a399bba1589409d72154ff87c1282" dependencies = [ - "web-time", + "zeroize", ] [[package]] name = "rustls-platform-verifier" -version = "0.3.4" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afbb878bdfdf63a336a5e63561b1835e7a8c91524f51621db870169eac84b490" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" dependencies = [ - "core-foundation 0.9.4", + "core-foundation 0.10.0", "core-foundation-sys", - "jni 0.19.0", + "jni", "log", "once_cell", - "rustls 0.23.20", - "rustls-native-certs 0.7.3", + "rustls 0.23.35", + "rustls-native-certs 0.8.3", "rustls-platform-verifier-android", - "rustls-webpki 0.102.8", - "security-framework", + "rustls-webpki 0.103.8", + "security-framework 3.5.1", "security-framework-sys", - "webpki-roots 0.26.7", - "winapi", + "webpki-root-certs", + "windows-sys 0.60.2", ] [[package]] @@ -7272,6 +7247,17 @@ dependencies = [ "untrusted", ] +[[package]] +name = "rustls-webpki" +version = "0.103.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", +] + [[package]] name = "rustversion" version = "1.0.19" @@ -7470,15 +7456,27 @@ dependencies = [ "core-foundation 0.9.4", "core-foundation-sys", "libc", - "num-bigint", + "security-framework-sys", +] + +[[package]] +name = "security-framework" +version = "3.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" +dependencies = [ + "bitflags 2.7.0", + "core-foundation 0.10.0", + "core-foundation-sys", + "libc", "security-framework-sys", ] [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -7519,10 +7517,11 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -7571,10 +7570,19 @@ dependencies = [ ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "serde_core" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -7603,15 +7611,16 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.140" +version = "1.0.145" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" +checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.11.4", "itoa", "memchr", "ryu", "serde", + "serde_core", ] [[package]] @@ -7646,11 +7655,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -7675,7 +7684,7 @@ dependencies = [ "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.7.0", + "indexmap 2.11.4", "serde", "serde_derive", "serde_json", @@ -7701,7 +7710,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.11.4", "itoa", "ryu", "serde", @@ -7844,9 +7853,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook" -version = "0.3.17" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8621587d4798caf8eb44879d42e56b9a93ea5dcd315a6487c357130095b62801" +checksum = "2a37d01603c37b5466f808de79f845c7116049b0579adb70a6b7d47c1fa3a952" dependencies = [ "libc", "signal-hook-registry", @@ -7863,9 +7872,9 @@ dependencies = [ [[package]] name = "signal-hook-tokio" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213241f76fb1e37e27de3b6aa1b068a2c333233b59cca6634f634b80a27ecf1e" +checksum = "e513e435a8898a0002270f29d0a708b7879708fb5c4d00e46983ca2d2d378cf0" dependencies = [ "futures-core", "libc", @@ -8000,6 +8009,16 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "socket2" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + [[package]] name = "socks" version = "0.3.4" @@ -8411,9 +8430,9 @@ dependencies = [ [[package]] name = "tao" -version = "0.34.2" +version = "0.34.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4daa814018fecdfb977b59a094df4bd43b42e8e21f88fddfc05807e6f46efaaf" +checksum = "f3a753bdc39c07b192151523a3f77cd0394aa75413802c883a0f6f6a0e5ee2e7" dependencies = [ "bitflags 2.7.0", "block2 0.6.0", @@ -8426,7 +8445,7 @@ dependencies = [ "gdkwayland-sys", "gdkx11-sys", "gtk", - "jni 0.21.1", + "jni", "lazy_static", "libc", "log", @@ -8485,7 +8504,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.8.5" +version = "2.9.5" dependencies = [ "anyhow", "bytes", @@ -8502,7 +8521,7 @@ dependencies = [ "http 1.3.1", "http-range", "image", - "jni 0.21.1", + "jni", "libc", "log", "mime", @@ -8518,7 +8537,8 @@ dependencies = [ "quickcheck", "quickcheck_macros", "raw-window-handle", - "reqwest 0.12.12", + "reqwest 0.13.1", + "rustls 0.23.35", "serde", "serde_json", "serde_repr", @@ -8536,7 +8556,6 @@ dependencies = [ "tracing", "tray-icon", "url", - "urlpattern", "uuid", "webkit2gtk", "webview2-com", @@ -8546,7 +8565,7 @@ dependencies = [ [[package]] name = "tauri-build" -version = "2.4.1" +version = "2.5.3" dependencies = [ "anyhow", "cargo_toml", @@ -8562,13 +8581,13 @@ dependencies = [ "tauri-codegen", "tauri-utils", "tauri-winres", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", "walkdir", ] [[package]] name = "tauri-bundler" -version = "2.6.1" +version = "2.7.5" dependencies = [ "anyhow", "ar", @@ -8607,14 +8626,14 @@ dependencies = [ "uuid", "walkdir", "which", - "windows-registry 0.5.0", + "windows-registry", "windows-sys 0.60.2", "zip 4.0.0", ] [[package]] name = "tauri-cli" -version = "2.8.4" +version = "2.9.6" dependencies = [ "ar", "axum", @@ -8668,6 +8687,7 @@ dependencies = [ "plist", "pretty_assertions", "rand 0.9.1", + "rayon", "regex", "resvg", "semver", @@ -8683,8 +8703,8 @@ dependencies = [ "tempfile", "thiserror 2.0.12", "tokio", - "toml 0.9.4", - "toml_edit 0.23.2", + "toml 0.9.10+spec-1.1.0", + "toml_edit 0.24.0+spec-1.1.0", "ureq", "url", "uuid", @@ -8707,7 +8727,7 @@ dependencies = [ [[package]] name = "tauri-codegen" -version = "2.4.0" +version = "2.5.2" dependencies = [ "base64 0.22.1", "brotli", @@ -8738,7 +8758,7 @@ dependencies = [ "futures", "futures-util", "http-body-util", - "hyper 1.5.2", + "hyper 1.8.1", "hyper-util", "pico-args", "serde", @@ -8773,17 +8793,18 @@ dependencies = [ [[package]] name = "tauri-macos-sign" -version = "2.2.0" +version = "2.3.2" dependencies = [ "apple-codesign", "chrono", "dirs 6.0.0", "log", - "once-cell-regex", + "once_cell", "os_pipe", "p12", "plist", "rand 0.9.1", + "regex", "serde", "serde_json", "tempfile", @@ -8793,7 +8814,7 @@ dependencies = [ [[package]] name = "tauri-macros" -version = "2.4.0" +version = "2.5.2" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -8805,7 +8826,7 @@ dependencies = [ [[package]] name = "tauri-plugin" -version = "2.4.0" +version = "2.5.2" dependencies = [ "anyhow", "glob", @@ -8814,7 +8835,7 @@ dependencies = [ "serde", "serde_json", "tauri-utils", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", "walkdir", ] @@ -8853,13 +8874,13 @@ dependencies = [ [[package]] name = "tauri-runtime" -version = "2.8.0" +version = "2.9.2" dependencies = [ "cookie", "dpi", "gtk", "http 1.3.1", - "jni 0.21.1", + "jni", "objc2 0.6.0", "objc2-ui-kit", "objc2-web-kit", @@ -8876,11 +8897,11 @@ dependencies = [ [[package]] name = "tauri-runtime-wry" -version = "2.8.1" +version = "2.9.3" dependencies = [ "gtk", "http 1.3.1", - "jni 0.21.1", + "jni", "log", "objc2 0.6.0", "objc2-app-kit", @@ -8927,7 +8948,7 @@ dependencies = [ [[package]] name = "tauri-utils" -version = "2.7.0" +version = "2.8.1" dependencies = [ "aes-gcm", "anyhow", @@ -8958,8 +8979,9 @@ dependencies = [ "serial_test", "serialize-to-javascript", "swift-rs", + "tauri", "thiserror 2.0.12", - "toml 0.9.4", + "toml 0.9.10+spec-1.1.0", "url", "urlpattern", "uuid", @@ -8973,8 +8995,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c6d9028d41d4de835e3c482c677a8cb88137ac435d6ff9a71f392d4421576c9" dependencies = [ "embed-resource", - "indexmap 2.7.0", - "toml 0.9.4", + "indexmap 2.11.4", + "toml 0.9.10+spec-1.1.0", ] [[package]] @@ -9205,7 +9227,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2", + "socket2 0.5.8", "tokio-macros", "windows-sys 0.52.0", ] @@ -9247,7 +9269,7 @@ version = "0.26.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f6d0975eaace0cf0fcadee4e4aaa5da15b5c079146f2cffb67c113be122bf37" dependencies = [ - "rustls 0.23.20", + "rustls 0.23.35", "tokio", ] @@ -9303,17 +9325,17 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.4" +version = "0.9.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41ae868b5a0f67631c14589f7e250c1ea2c574ee5ba21c6c8dd4b1485705a5a1" +checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48" dependencies = [ - "indexmap 2.7.0", - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", + "indexmap 2.11.4", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.11", + "winnow 0.7.14", ] [[package]] @@ -9327,11 +9349,11 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "0.7.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -9340,7 +9362,7 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.11.4", "toml_datetime 0.6.8", "winnow 0.5.40", ] @@ -9351,7 +9373,7 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.11.4", "toml_datetime 0.6.8", "winnow 0.5.40", ] @@ -9362,42 +9384,42 @@ version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ - "indexmap 2.7.0", + "indexmap 2.11.4", "serde", "serde_spanned 0.6.8", "toml_datetime 0.6.8", - "winnow 0.7.11", + "winnow 0.7.14", ] [[package]] name = "toml_edit" -version = "0.23.2" +version = "0.24.0+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1dee9dc43ac2aaf7d3b774e2fba5148212bf2bd9374f4e50152ebe9afd03d42" +checksum = "8c740b185920170a6d9191122cafef7010bd6270a3824594bff6784c04d7f09e" dependencies = [ - "indexmap 2.7.0", - "serde", - "serde_spanned 1.0.0", - "toml_datetime 0.7.0", + "indexmap 2.11.4", + "serde_core", + "serde_spanned 1.0.4", + "toml_datetime 0.7.5+spec-1.1.0", "toml_parser", "toml_writer", - "winnow 0.7.11", + "winnow 0.7.14", ] [[package]] name = "toml_parser" -version = "1.0.1" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" dependencies = [ - "winnow 0.7.11", + "winnow 0.7.14", ] [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.0.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" [[package]] name = "tower" @@ -9430,6 +9452,24 @@ dependencies = [ "tracing", ] +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "bitflags 2.7.0", + "bytes", + "futures-util", + "http 1.3.1", + "http-body 1.0.1", + "iri-string", + "pin-project-lite", + "tower 0.5.2", + "tower-layer", + "tower-service", +] + [[package]] name = "tower-layer" version = "0.3.3" @@ -9769,33 +9809,31 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.0.3" +version = "3.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "217751151c53226090391713e533d9a5e904ba2570dabaaace29032687589c3e" +checksum = "d39cb1dbab692d82a977c0392ffac19e188bd9186a9f32806f0aaa859d75585a" dependencies = [ "base64 0.22.1", - "cc", "der", "flate2", "log", "native-tls", "percent-encoding", - "rustls 0.23.20", - "rustls-pemfile 2.2.0", + "rustls 0.23.35", "rustls-pki-types", "rustls-platform-verifier", "socks", "ureq-proto", "utf-8", "webpki-root-certs", - "webpki-roots 0.26.7", + "webpki-roots 1.0.5", ] [[package]] name = "ureq-proto" -version = "0.3.0" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c51fe73e1d8c4e06bb2698286f7e7453c6fc90528d6d2e7fc36bb4e87fe09b1" +checksum = "d81f9efa9df032be5934a46a068815a10a042b494b6a58cb0a1a97bb5467ed6f" dependencies = [ "base64 0.22.1", "http 1.3.1", @@ -9919,9 +9957,9 @@ dependencies = [ [[package]] name = "value-bag" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ef4c4aa54d5d05a279399bfa921ec387b7aba77caf7a682ae8d86785b8fdad2" +checksum = "7ba6f5989077681266825251a52748b8c1d8a4ad098cc37e440103d0ea717fc0" dependencies = [ "value-bag-serde1", "value-bag-sval2", @@ -9929,20 +9967,20 @@ dependencies = [ [[package]] name = "value-bag-serde1" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb773bd36fd59c7ca6e336c94454d9c66386416734817927ac93d81cb3c5b0b" +checksum = "16530907bfe2999a1773ca5900a65101e092c70f642f25cc23ca0c43573262c5" dependencies = [ "erased-serde", - "serde", + "serde_core", "serde_fmt", ] [[package]] name = "value-bag-sval2" -version = "1.10.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53a916a702cac43a88694c97657d449775667bcd14b70419441d05b7fea4a83a" +checksum = "d00ae130edd690eaa877e4f40605d534790d1cf1d651e7685bd6a144521b251f" dependencies = [ "sval", "sval_buffer", @@ -10054,35 +10092,22 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.95", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c" dependencies = [ "cfg-if", "js-sys", @@ -10093,9 +10118,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10103,22 +10128,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40" dependencies = [ + "bumpalo", "proc-macro2", "quote", "syn 2.0.95", - "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4" dependencies = [ "unicode-ident", ] @@ -10138,19 +10163,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - -[[package]] -name = "web-time" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac" dependencies = [ "js-sys", "wasm-bindgen", @@ -10158,9 +10173,9 @@ dependencies = [ [[package]] name = "webkit2gtk" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76b1bc1e54c581da1e9f179d0b38512ba358fb1af2d634a1affe42e37172361a" +checksum = "a1027150013530fb2eaf806408df88461ae4815a45c541c8975e61d6f2fc4793" dependencies = [ "bitflags 1.3.2", "cairo-rs", @@ -10182,9 +10197,9 @@ dependencies = [ [[package]] name = "webkit2gtk-sys" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62daa38afc514d1f8f12b8693d30d5993ff77ced33ce30cd04deebc267a6d57c" +checksum = "916a5f65c2ef0dfe12fff695960a2ec3d4565359fdbb2e9943c974e06c734ea5" dependencies = [ "bitflags 1.3.2", "cairo-sys-rs", @@ -10202,9 +10217,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "0.26.7" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cd5da49bdf1f30054cfe0b8ce2958b8fbeb67c4d82c8967a598af481bef255c" +checksum = "36a29fc0408b113f68cf32637857ab740edfafdf460c326cd2afaa2d84cc05dc" dependencies = [ "rustls-pki-types", ] @@ -10217,9 +10232,9 @@ checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "webpki-roots" -version = "0.26.7" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ "rustls-pki-types", ] @@ -10315,7 +10330,7 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" dependencies = [ - "windows-sys 0.48.0", + "windows-sys 0.59.0", ] [[package]] @@ -10389,7 +10404,7 @@ dependencies = [ "windows-implement", "windows-interface", "windows-link", - "windows-result 0.3.2", + "windows-result", "windows-strings 0.4.0", ] @@ -10441,17 +10456,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-registry" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" -dependencies = [ - "windows-result 0.2.0", - "windows-strings 0.1.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-registry" version = "0.5.0" @@ -10459,19 +10463,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6c44a98275e31bfd112bb06ba96c8ab13c03383a3753fdddd715406a1824c7e0" dependencies = [ "windows-link", - "windows-result 0.3.2", + "windows-result", "windows-strings 0.3.1", ] -[[package]] -name = "windows-result" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" -dependencies = [ - "windows-targets 0.52.6", -] - [[package]] name = "windows-result" version = "0.3.2" @@ -10481,16 +10476,6 @@ dependencies = [ "windows-link", ] -[[package]] -name = "windows-strings" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" -dependencies = [ - "windows-result 0.2.0", - "windows-targets 0.52.6", -] - [[package]] name = "windows-strings" version = "0.3.1" @@ -10816,9 +10801,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.11" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -10860,9 +10845,9 @@ dependencies = [ [[package]] name = "worker" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6ac1566a3005b790b974f0621d77431e2a47e5f481276485f5ac0485775de2" +checksum = "42c76c5889873a2c309365ad4503810c007d3c25fbb4e9fa9e4e23c4ceb3c7f2" dependencies = [ "async-trait", "axum", @@ -10885,31 +10870,15 @@ dependencies = [ "wasm-bindgen-futures", "wasm-streams", "web-sys", - "worker-kv", "worker-macros", "worker-sys", ] -[[package]] -name = "worker-kv" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0d30eb90e8db0657414129624c0d12c6cb480574bc2ddd584822db196cb9a52" -dependencies = [ - "js-sys", - "serde", - "serde-wasm-bindgen", - "serde_json", - "thiserror 2.0.12", - "wasm-bindgen", - "wasm-bindgen-futures", -] - [[package]] name = "worker-macros" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ba7478759843ae3d56dc7ba2445e7a514a5d043eaa98cebac2789f7ab5221ee" +checksum = "62c62584d037bad33789a6a5d605b3fccea1c52de9251d06f9d44054170dc612" dependencies = [ "async-trait", "proc-macro2", @@ -10923,9 +10892,9 @@ dependencies = [ [[package]] name = "worker-sys" -version = "0.6.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb4d7a3273dd584b9526aec77bbcf815c51d1a0e17407b1a390cf5a39b6d4fbd" +checksum = "72ddd412fd62c6eeffc1dd85e6ae5960a33b534f44a733df75b6e7519972bc74" dependencies = [ "cfg-if", "js-sys", @@ -10947,9 +10916,9 @@ checksum = "1e9df38ee2d2c3c5948ea468a8406ff0db0b29ae1ffde1bcf20ef305bcc95c51" [[package]] name = "wry" -version = "0.53.2" +version = "0.54.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b6763512fe4b51c80b3ce9b50939d682acb4de335dfabbdb20d7a2642199b7" +checksum = "e456eeaf7f09413fdc16799782879b2b9f1d264dfdbce4cf7e924df0ef36afb9" dependencies = [ "base64 0.22.1", "block2 0.6.0", @@ -10963,7 +10932,7 @@ dependencies = [ "html5ever", "http 1.3.1", "javascriptcore-rs", - "jni 0.21.1", + "jni", "kuchikiki", "libc", "ndk", @@ -11265,7 +11234,7 @@ dependencies = [ "arbitrary", "crc32fast", "flate2", - "indexmap 2.7.0", + "indexmap 2.11.4", "memchr", "zopfli", ] diff --git a/crates/tauri-build/CHANGELOG.md b/crates/tauri-build/CHANGELOG.md index 5b3c82913..4e5c9c97a 100644 --- a/crates/tauri-build/CHANGELOG.md +++ b/crates/tauri-build/CHANGELOG.md @@ -1,5 +1,35 @@ # Changelog +## \[2.5.3] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` +- Upgraded to `tauri-codegen@2.5.2` + +## \[2.5.2] + +### Dependencies + +- Upgraded to `tauri-codegen@2.5.1` + +## \[2.5.1] + +### Bug Fixes + +- [`4b6b8690a`](https://www.github.com/tauri-apps/tauri/commit/4b6b8690ab886ebdf1307951cffbe03e31280baa) ([#14347](https://www.github.com/tauri-apps/tauri/pull/14347) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + +## \[2.5.0] + +### New Features + +- [`3b4fac201`](https://www.github.com/tauri-apps/tauri/commit/3b4fac2017832d426dd07c5e24e26684eda57f7b) ([#14194](https://www.github.com/tauri-apps/tauri/pull/14194)) Add `tauri.conf.json > bundle > android > autoIncrementVersionCode` config option to automatically increment the Android version code. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- Upgraded to `tauri-codegen@2.5.0` + ## \[2.4.1] ### Enhancements diff --git a/crates/tauri-build/Cargo.toml b/crates/tauri-build/Cargo.toml index c52bd7ee7..da35d963b 100644 --- a/crates/tauri-build/Cargo.toml +++ b/crates/tauri-build/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-build" -version = "2.4.1" +version = "2.5.3" description = "build time code to pair with https://crates.io/crates/tauri" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -22,14 +22,12 @@ targets = [ "x86_64-linux-android", "x86_64-apple-ios", ] -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] [dependencies] anyhow = "1" quote = { version = "1", optional = true } -tauri-codegen = { version = "2.4.0", path = "../tauri-codegen", optional = true } -tauri-utils = { version = "2.7.0", path = "../tauri-utils", features = [ +tauri-codegen = { version = "2.5.2", path = "../tauri-codegen", optional = true } +tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [ "build", "resources", ] } diff --git a/crates/tauri-build/src/acl.rs b/crates/tauri-build/src/acl.rs index 474c63006..16f529d6a 100644 --- a/crates/tauri-build/src/acl.rs +++ b/crates/tauri-build/src/acl.rs @@ -157,7 +157,7 @@ fn read_plugins_manifests() -> Result> { Ok(manifests) } -struct InlinedPuginsAcl { +struct InlinedPluginsAcl { manifests: BTreeMap, permission_files: BTreeMap>, } @@ -165,7 +165,7 @@ struct InlinedPuginsAcl { fn inline_plugins( out_dir: &Path, inlined_plugins: HashMap<&'static str, InlinedPlugin>, -) -> Result { +) -> Result { let mut acl_manifests = BTreeMap::new(); let mut permission_files_map = BTreeMap::new(); @@ -250,7 +250,7 @@ permissions = [{default_permissions}] acl_manifests.insert(name.into(), manifest); } - Ok(InlinedPuginsAcl { + Ok(InlinedPluginsAcl { manifests: acl_manifests, permission_files: permission_files_map, }) diff --git a/crates/tauri-build/src/lib.rs b/crates/tauri-build/src/lib.rs index 5e392d210..42c9275b4 100644 --- a/crates/tauri-build/src/lib.rs +++ b/crates/tauri-build/src/lib.rs @@ -165,21 +165,21 @@ fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> { .with_context(|| format!("Failed to create frameworks output directory at {dest_dir:?}"))?; for framework in frameworks.iter() { if framework.ends_with(".framework") { - let src_path = PathBuf::from(framework); + let src_path = Path::new(framework); let src_name = src_path .file_name() .expect("Couldn't get framework filename"); let dest_path = dest_dir.join(src_name); - copy_dir(&src_path, &dest_path)?; + copy_dir(src_path, &dest_path)?; continue; } else if framework.ends_with(".dylib") { - let src_path = PathBuf::from(framework); + let src_path = Path::new(framework); if !src_path.exists() { return Err(anyhow::anyhow!("Library not found: {}", framework)); } let src_name = src_path.file_name().expect("Couldn't get library filename"); let dest_path = dest_dir.join(src_name); - copy_file(&src_path, &dest_path)?; + copy_file(src_path, &dest_path)?; continue; } else if framework.contains('/') { return Err(anyhow::anyhow!( @@ -192,12 +192,8 @@ fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> { continue; } } - if copy_framework_from(&PathBuf::from("/Library/Frameworks/"), framework, dest_dir)? - || copy_framework_from( - &PathBuf::from("/Network/Library/Frameworks/"), - framework, - dest_dir, - )? + if copy_framework_from("/Library/Frameworks/".as_ref(), framework, dest_dir)? + || copy_framework_from("/Network/Library/Frameworks/".as_ref(), framework, dest_dir)? { continue; } @@ -263,7 +259,7 @@ impl WindowsAttributes { } } - /// Creates the default attriute set wihtou the default app manifest. + /// Creates the default attribute set without the default app manifest. #[must_use] pub fn new_without_app_manifest() -> Self { Self { @@ -499,7 +495,7 @@ pub fn try_build(attributes: Attributes) -> Result<()> { println!("cargo:rustc-env=TAURI_ANDROID_PACKAGE_NAME_PREFIX={android_package_prefix}"); if let Some(project_dir) = env::var_os("TAURI_ANDROID_PROJECT_PATH").map(PathBuf::from) { - mobile::generate_gradle_files(project_dir, &config)?; + mobile::generate_gradle_files(project_dir)?; } cfg_alias("dev", is_dev()); diff --git a/crates/tauri-build/src/mobile.rs b/crates/tauri-build/src/mobile.rs index 836b0d935..9acef2e91 100644 --- a/crates/tauri-build/src/mobile.rs +++ b/crates/tauri-build/src/mobile.rs @@ -2,18 +2,14 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use std::{fs::write, path::PathBuf}; +use std::path::PathBuf; use anyhow::{Context, Result}; -use semver::Version; -use tauri_utils::{config::Config, write_if_changed}; +use tauri_utils::write_if_changed; -use crate::is_dev; - -pub fn generate_gradle_files(project_dir: PathBuf, config: &Config) -> Result<()> { +pub fn generate_gradle_files(project_dir: PathBuf) -> Result<()> { let gradle_settings_path = project_dir.join("tauri.settings.gradle"); let app_build_gradle_path = project_dir.join("app").join("tauri.build.gradle.kts"); - let app_tauri_properties_path = project_dir.join("app").join("tauri.properties"); let mut gradle_settings = "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n".to_string(); @@ -21,7 +17,6 @@ pub fn generate_gradle_files(project_dir: PathBuf, config: &Config) -> Result<() val implementation by configurations dependencies {" .to_string(); - let mut app_tauri_properties = Vec::new(); for (env, value) in std::env::vars_os() { let env = env.to_string_lossy(); @@ -54,32 +49,6 @@ dependencies {" app_build_gradle.push_str("\n}"); - if let Some(version) = config.version.as_ref() { - app_tauri_properties.push(format!("tauri.android.versionName={version}")); - if let Some(version_code) = config.bundle.android.version_code.as_ref() { - app_tauri_properties.push(format!("tauri.android.versionCode={version_code}")); - } else if let Ok(version) = Version::parse(version) { - let mut version_code = version.major * 1000000 + version.minor * 1000 + version.patch; - - if is_dev() { - version_code = version_code.clamp(1, 2100000000); - } - - if version_code == 0 { - return Err(anyhow::anyhow!( - "You must change the `version` in `tauri.conf.json`. The default value `0.0.0` is not allowed for Android package and must be at least `0.0.1`." - )); - } else if version_code > 2100000000 { - return Err(anyhow::anyhow!( - "Invalid version code {}. Version code must be between 1 and 2100000000. You must change the `version` in `tauri.conf.json`.", - version_code - )); - } - - app_tauri_properties.push(format!("tauri.android.versionCode={version_code}")); - } - } - // Overwrite only if changed to not trigger rebuilds write_if_changed(&gradle_settings_path, gradle_settings) .context("failed to write tauri.settings.gradle")?; @@ -87,28 +56,8 @@ dependencies {" write_if_changed(&app_build_gradle_path, app_build_gradle) .context("failed to write tauri.build.gradle.kts")?; - if !app_tauri_properties.is_empty() { - let app_tauri_properties_content = format!( - "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n{}", - app_tauri_properties.join("\n") - ); - if std::fs::read_to_string(&app_tauri_properties_path) - .map(|o| o != app_tauri_properties_content) - .unwrap_or(true) - { - write(&app_tauri_properties_path, app_tauri_properties_content) - .context("failed to write tauri.properties")?; - } - } - println!("cargo:rerun-if-changed={}", gradle_settings_path.display()); println!("cargo:rerun-if-changed={}", app_build_gradle_path.display()); - if !app_tauri_properties.is_empty() { - println!( - "cargo:rerun-if-changed={}", - app_tauri_properties_path.display() - ); - } Ok(()) } diff --git a/crates/tauri-bundler/CHANGELOG.md b/crates/tauri-bundler/CHANGELOG.md index bfc358258..c8e880524 100644 --- a/crates/tauri-bundler/CHANGELOG.md +++ b/crates/tauri-bundler/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## \[2.7.5] + +### Enhancements + +- [`4176f93ae`](https://www.github.com/tauri-apps/tauri/commit/4176f93ae43ef66714c4934feb3df19df3a3e28a) ([#14570](https://www.github.com/tauri-apps/tauri/pull/14570) by [@chfaft](https://www.github.com/tauri-apps/tauri/../../chfaft)) Consider extensions that are defined in the wxs template. + +### Bug Fixes + +- [`018b4db22`](https://www.github.com/tauri-apps/tauri/commit/018b4db22e167fa67b37b0933e192a0f3556d3e5) ([#14625](https://www.github.com/tauri-apps/tauri/pull/14625) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Skip signing for NSIS uninstaller when using `--no-sign` flag +- [`91becd9e4`](https://www.github.com/tauri-apps/tauri/commit/91becd9e4fa2db089ddc6b21dadc06133e939e08) ([#14627](https://www.github.com/tauri-apps/tauri/pull/14627) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix NSIS plugins not being signed due to wrong path handlings + +### Dependencies + +- Upgraded to `tauri-macos-sign@2.3.2` + +## \[2.7.4] + +### Bug Fixes + +- [`1496145f8`](https://www.github.com/tauri-apps/tauri/commit/1496145f8222649efeff22b819a96208670bbea1) ([#14585](https://www.github.com/tauri-apps/tauri/pull/14585) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused the AppImage bundler to fail with 404 errors for 32-bit builds. + +### Performance Improvements + +- [`ce98d87ce`](https://www.github.com/tauri-apps/tauri/commit/ce98d87ce0aaa907285852eb80691197424e03c3) ([#14474](https://www.github.com/tauri-apps/tauri/pull/14474) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) refactor: remove needless collect. No user facing changes. +- [`ee3cc4a91`](https://www.github.com/tauri-apps/tauri/commit/ee3cc4a91bf1315ecaefe90f423ffd55ef6c40db) ([#14475](https://www.github.com/tauri-apps/tauri/pull/14475) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) perf: remove needless clones in various files for improved performance. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-macos-sign@2.3.1` +- Upgraded to `tauri-utils@2.8.1` +- [`b5ef603d8`](https://www.github.com/tauri-apps/tauri/commit/b5ef603d84bd8044625e50dcfdabb099b2e9fdd9) ([#14478](https://www.github.com/tauri-apps/tauri/pull/14478) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Updated NSIS from 3.8 to 3.11 + +## \[2.7.3] + +### Enhancements + +- [`22edc65aa`](https://www.github.com/tauri-apps/tauri/commit/22edc65aad0b3e45515008e8e0866112da70c8a1) ([#14408](https://www.github.com/tauri-apps/tauri/pull/14408) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Set user-agent in bundler and cli http requests when fetching build tools. + +### Bug Fixes + +- [`9a1922636`](https://www.github.com/tauri-apps/tauri/commit/9a192263693d71123a9953e2a6ee60fad07500b4) ([#14410](https://www.github.com/tauri-apps/tauri/pull/14410) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix uninstall fails if you close the app manually during the 'Click Ok to kill it' dialog + +## \[2.7.2] + +### Enhancements + +- [`7f710b8f3`](https://www.github.com/tauri-apps/tauri/commit/7f710b8f3b509ed327d76761926511cf56e66b2d) ([#14390](https://www.github.com/tauri-apps/tauri/pull/14390) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Inline linuxdeploy plugins which were previously downloaded from `https://raw.githubusercontent.com` which lately blocks many users with a 429 error. +- [`fc017ee25`](https://www.github.com/tauri-apps/tauri/commit/fc017ee2577f48615367ea519386d3f37837e2c1) ([#14368](https://www.github.com/tauri-apps/tauri/pull/14368) by [@kandrelczyk](https://www.github.com/tauri-apps/tauri/../../kandrelczyk)) Mention symbol stripping on Linux in binary patch failed warning message + +## \[2.7.1] + +### Dependencies + +- Upgraded to `tauri-macos-sign@2.3.0` + +## \[2.7.0] + +### New Features + +- [`2a06d1006`](https://www.github.com/tauri-apps/tauri/commit/2a06d10066a806e392efe8bfb16d943ee0b0b61d) ([#14052](https://www.github.com/tauri-apps/tauri/pull/14052)) Add a `--no-sign` flag to the `tauri build` and `tauri bundle` commands to skip the code signing step, improving the developer experience for local testing and development without requiring code signing keys. +- [`cc8c0b531`](https://www.github.com/tauri-apps/tauri/commit/cc8c0b53171173dbd1d01781a50de1a3ea159031) ([#14031](https://www.github.com/tauri-apps/tauri/pull/14031)) Support providing `plist::Value` as macOS entitlements. + +### Enhancements + +- [`b06b3bd09`](https://www.github.com/tauri-apps/tauri/commit/b06b3bd091b0fed26cdcfb23cacb0462a7a9cc2d) ([#14126](https://www.github.com/tauri-apps/tauri/pull/14126)) Improve error messages with more context. + +### Bug Fixes + +- [`06d4a4ed6`](https://www.github.com/tauri-apps/tauri/commit/06d4a4ed6c146d6c7782016cf90037b56b944445) ([#14241](https://www.github.com/tauri-apps/tauri/pull/14241)) Set `APPIMAGE_EXTRACT_AND_RUN` on top of using the `--appimage-extra-and-run` cli arg for linuxdeploy. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` + +### Breaking Changes + +- [`ed7c9a410`](https://www.github.com/tauri-apps/tauri/commit/ed7c9a4100e08c002212265549d12130d021ad1e) ([#14108](https://www.github.com/tauri-apps/tauri/pull/14108)) Changed `MacOsSettings::info_plist_path` to `MacOsSettings::info_plist`. + ## \[2.6.1] ### Bug Fixes diff --git a/crates/tauri-bundler/Cargo.toml b/crates/tauri-bundler/Cargo.toml index 37e19f4f7..cb88cb9a9 100644 --- a/crates/tauri-bundler/Cargo.toml +++ b/crates/tauri-bundler/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-bundler" -version = "2.6.1" +version = "2.7.5" authors = [ "George Burton ", "Tauri Programme within The Commons Conservancy", @@ -15,7 +15,7 @@ rust-version = "1.77.2" exclude = ["CHANGELOG.md", "/target", "rustfmt.toml"] [dependencies] -tauri-utils = { version = "2.7.0", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [ "resources", ] } image = "0.25" @@ -59,7 +59,7 @@ features = ["Win32_System_SystemInformation", "Win32_System_Diagnostics_Debug"] [target."cfg(target_os = \"macos\")".dependencies] icns = { package = "tauri-icns", version = "0.1" } time = { version = "0.3", features = ["formatting"] } -tauri-macos-sign = { version = "2.2.0", path = "../tauri-macos-sign" } +tauri-macos-sign = { version = "2.3.2", path = "../tauri-macos-sign" } [target."cfg(target_os = \"linux\")".dependencies] heck = "0.5" diff --git a/crates/tauri-bundler/src/bundle.rs b/crates/tauri-bundler/src/bundle.rs index c5a3acc81..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() { @@ -241,11 +255,10 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { return Ok(bundles); } - let bundles_wo_updater = bundles + let finished_bundles = bundles .iter() .filter(|b| b.package_type != PackageType::Updater) - .collect::>(); - let finished_bundles = bundles_wo_updater.len(); + .count(); let pluralised = if finished_bundles == 1 { "bundle" } else { @@ -274,7 +287,7 @@ fn sign_binaries_if_needed(settings: &Settings, target_os: &TargetPlatform) -> c if matches!(target_os, TargetPlatform::Windows) { if settings.windows().can_sign() { if settings.no_sign() { - log::info!("Skipping binary signing due to --no-sign flag."); + log::warn!("Skipping binary signing due to --no-sign flag."); return Ok(()); } 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-plugin-gstreamer.sh b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gstreamer.sh new file mode 100644 index 000000000..757afd4f0 --- /dev/null +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gstreamer.sh @@ -0,0 +1,165 @@ +#! /bin/bash + +# abort on all errors +set -e + +if [ "$DEBUG" != "" ]; then + set -x +fi + +script=$(readlink -f "$0") + +show_usage() { + echo "Usage: $script --appdir " + echo + echo "Bundles GStreamer plugins into an AppDir" + echo + echo "Required variables:" + echo " LINUXDEPLOY=\".../linuxdeploy\" path to linuxdeploy (e.g., AppImage); set automatically when plugin is run directly by linuxdeploy" + echo + echo "Optional variables:" + echo " GSTREAMER_INCLUDE_BAD_PLUGINS=\"1\" (default: disabled; set to empty string or unset to disable)" + echo " GSTREAMER_PLUGINS_DIR=\"...\" (directory containing GStreamer plugins; default: guessed based on main distro architecture)" + echo " GSTREAMER_HELPERS_DIR=\"...\" (directory containing GStreamer helper tools like gst-plugin-scanner; default: guessed based on main distro architecture)" + echo " GSTREAMER_VERSION=\"1.0\" (default: 1.0)" +} + +while [ "$1" != "" ]; do + case "$1" in + --plugin-api-version) + echo "0" + exit 0 + ;; + --appdir) + APPDIR="$2" + shift + shift + ;; + --help) + show_usage + exit 0 + ;; + *) + echo "Invalid argument: $1" + echo + show_usage + exit 1 + ;; + esac +done + +if [ "$APPDIR" == "" ]; then + show_usage + exit 1 +fi + +if ! which patchelf &>/dev/null && ! type patchelf &>/dev/null; then + echo "Error: patchelf not found" + echo + show_usage + exit 2 +fi + +if [[ "$LINUXDEPLOY" == "" ]]; then + echo "Error: \$LINUXDEPLOY not set" + echo + show_usage + exit 3 +fi + +mkdir -p "$APPDIR" + +export GSTREAMER_VERSION="${GSTREAMER_VERSION:-1.0}" + +plugins_target_dir="$APPDIR"/usr/lib/gstreamer-"$GSTREAMER_VERSION" +helpers_target_dir="$APPDIR"/usr/lib/gstreamer"$GSTREAMER_VERSION"/gstreamer-"$GSTREAMER_VERSION" + +if [ "$GSTREAMER_PLUGINS_DIR" != "" ]; then + plugins_dir="${GSTREAMER_PLUGINS_DIR}" +elif [ -d /usr/lib/"$(uname -m)"-linux-gnu/gstreamer-"$GSTREAMER_VERSION" ]; then + plugins_dir=/usr/lib/$(uname -m)-linux-gnu/gstreamer-"$GSTREAMER_VERSION" +else + plugins_dir=/usr/lib/gstreamer-"$GSTREAMER_VERSION" +fi + +if [ "$GSTREAMER_HELPERS_DIR" != "" ]; then + helpers_dir="${GSTREAMER_HELPERS_DIR}" +else + helpers_dir=/usr/lib/$(uname -m)-linux-gnu/gstreamer"$GSTREAMER_VERSION"/gstreamer-"$GSTREAMER_VERSION" +fi + +if [ ! -d "$plugins_dir" ]; then + echo "Error: could not find plugins directory: $plugins_dir" + exit 1 +fi + +mkdir -p "$plugins_target_dir" + +echo "Copying plugins into $plugins_target_dir" +for i in "$plugins_dir"/*; do + [ -d "$i" ] && continue + [ ! -f "$i" ] && echo "File does not exist: $i" && continue + + echo "Copying plugin: $i" + cp "$i" "$plugins_target_dir" +done + +"$LINUXDEPLOY" --appdir "$APPDIR" + +for i in "$plugins_target_dir"/*; do + [ -d "$i" ] && continue + [ ! -f "$i" ] && echo "File does not exist: $i" && continue + (file "$i" | grep -v ELF --silent) && echo "Ignoring non ELF file: $i" && continue + + echo "Manually setting rpath for $i" + patchelf --set-rpath '$ORIGIN/..:$ORIGIN' "$i" +done + +mkdir -p "$helpers_target_dir" + +echo "Copying helpers in $helpers_target_dir" +for i in "$helpers_dir"/*; do + [ -d "$i" ] && continue + [ ! -f "$i" ] && echo "File does not exist: $i" && continue + + echo "Copying helper: $i" + cp "$i" "$helpers_target_dir" +done + +for i in "$helpers_target_dir"/*; do + [ -d "$i" ] && continue + [ ! -f "$i" ] && echo "File does not exist: $i" && continue + (file "$i" | grep -v ELF --silent) && echo "Ignoring non ELF file: $i" && continue + + echo "Manually setting rpath for $i" + patchelf --set-rpath '$ORIGIN/../..' "$i" +done + +echo "Installing AppRun hook" +mkdir -p "$APPDIR"/apprun-hooks + +if [ "$GSTREAMER_VERSION" == "1.0" ]; then + cat > "$APPDIR"/apprun-hooks/linuxdeploy-plugin-gstreamer.sh <<\EOF +#! /bin/bash + +export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no" +export GST_PLUGIN_SYSTEM_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0" +export GST_PLUGIN_PATH_1_0="${APPDIR}/usr/lib/gstreamer-1.0" + +export GST_PLUGIN_SCANNER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" +export GST_PTP_HELPER_1_0="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" +EOF +elif [ "$GSTREAMER_VERSION" == "0.10" ]; then + cat > "$APPDIR"/apprun-hooks/linuxdeploy-plugin-gstreamer.sh <<\EOF +#! /bin/bash + +export GST_REGISTRY_REUSE_PLUGIN_SCANNER="no" +export GST_PLUGIN_SYSTEM_PATH_0_10="${APPDIR}/usr/lib/gstreamer-1.0" + +export GST_PLUGIN_SCANNER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-plugin-scanner" +export GST_PTP_HELPER_0_10="${APPDIR}/usr/lib/gstreamer1.0/gstreamer-1.0/gst-ptp-helper" +EOF +else + echo "Warning: unknown GStreamer version: $GSTREAMER_VERSION, cannot install AppRun hook" +fi + diff --git a/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh new file mode 100644 index 000000000..b8e7f6f3a --- /dev/null +++ b/crates/tauri-bundler/src/bundle/linux/appimage/linuxdeploy-plugin-gtk.sh @@ -0,0 +1,327 @@ +#! /usr/bin/env bash + +# GTK3 environment variables: https://developer.gnome.org/gtk3/stable/gtk-running.html +# GTK4 environment variables: https://developer.gnome.org/gtk4/stable/gtk-running.html + +# abort on all errors +set -e + +if [ "$DEBUG" != "" ]; then + set -x + verbose="--verbose" +fi + +script=$(readlink -f "$0") + +show_usage() { + echo "Usage: $script --appdir " + echo + echo "Bundles resources for applications that use GTK into an AppDir" + echo + echo "Required variables:" + echo " LINUXDEPLOY=\".../linuxdeploy\" path to linuxdeploy (e.g., AppImage); set automatically when plugin is run directly by linuxdeploy" + #echo + #echo "Optional variables:" + #echo " DEPLOY_GTK_VERSION (major version of GTK to deploy, e.g. '2', '3' or '4'; auto-detect by default)" +} + +variable_is_true() { + local var="$1" + + if [ -n "$var" ] && { [ "$var" == "true" ] || [ "$var" -gt 0 ]; } 2> /dev/null; then + return 0 # true + else + return 1 # false + fi +} + +get_pkgconf_variable() { + local variable="$1" + local library="$2" + local default_path="$3" + + path="$("$PKG_CONFIG" --variable="$variable" "$library")" + if [ -n "$path" ]; then + echo "$path" + elif [ -n "$default_path" ]; then + echo "$default_path" + else + echo "$0: there is no '$variable' variable for '$library' library." > /dev/stderr + echo "Please check the '$library.pc' file is present in \$PKG_CONFIG_PATH (you may need to install the appropriate -dev/-devel package)." > /dev/stderr + exit 1 + fi +} + +copy_tree() { + local src=("${@:1:$#-1}") + local dst="${*:$#}" + + for elem in "${src[@]}"; do + mkdir -p "${dst::-1}$elem" + cp "$elem" --archive --parents --target-directory="$dst" $verbose + done +} + +search_tool() { + local tool="$1" + local directory="$2" + + if command -v "$tool"; then + return 0 + fi + + PATH_ARRAY=( + "/usr/lib/$(uname -m)-linux-gnu/$directory/$tool" + "/usr/lib/$directory/$tool" + "/usr/bin/$tool" + "/usr/bin/$tool-64" + "/usr/bin/$tool-32" + ) + + for path in "${PATH_ARRAY[@]}"; do + if [ -x "$path" ]; then + echo "$path" + return 0 + fi + done +} + +#DEPLOY_GTK_VERSION="${DEPLOY_GTK_VERSION:-0}" # When not set by user, this variable use the integer '0' as a sentinel value +DEPLOY_GTK_VERSION=3 # Force GTK3 for tauri apps +APPDIR= + +while [ "$1" != "" ]; do + case "$1" in + --plugin-api-version) + echo "0" + exit 0 + ;; + --appdir) + APPDIR="$2" + shift + shift + ;; + --help) + show_usage + exit 0 + ;; + *) + echo "Invalid argument: $1" + echo + show_usage + exit 1 + ;; + esac +done + +if [ "$APPDIR" == "" ]; then + show_usage + exit 1 +fi + +mkdir -p "$APPDIR" +# make lib64 writable again. +chmod +w "$APPDIR"/usr/lib64 || true + +if command -v pkgconf > /dev/null; then + PKG_CONFIG="pkgconf" +elif command -v pkg-config > /dev/null; then + PKG_CONFIG="pkg-config" +else + echo "$0: pkg-config/pkgconf not found in PATH, aborting" + exit 1 +fi + +if ! command -v find &>/dev/null && ! type find &>/dev/null; then + echo -e "$0: find not found.\nInstall findutils then re-run the plugin." + exit 1 +fi + +if [ -z "$LINUXDEPLOY" ]; then + echo -e "$0: LINUXDEPLOY environment variable is not set.\nDownload a suitable linuxdeploy AppImage, set the environment variable and re-run the plugin." + exit 1 +fi + +gtk_versions=0 # Count major versions of GTK when auto-detect GTK version +if [ "$DEPLOY_GTK_VERSION" -eq 0 ]; then + echo "Determining which GTK version to deploy" + while IFS= read -r -d '' file; do + if [ "$DEPLOY_GTK_VERSION" -ne 2 ] && ldd "$file" | grep -q "libgtk-x11-2.0.so"; then + DEPLOY_GTK_VERSION=2 + gtk_versions="$((gtk_versions+1))" + fi + if [ "$DEPLOY_GTK_VERSION" -ne 3 ] && ldd "$file" | grep -q "libgtk-3.so"; then + DEPLOY_GTK_VERSION=3 + gtk_versions="$((gtk_versions+1))" + fi + if [ "$DEPLOY_GTK_VERSION" -ne 4 ] && ldd "$file" | grep -q "libgtk-4.so"; then + DEPLOY_GTK_VERSION=4 + gtk_versions="$((gtk_versions+1))" + fi + done < <(find "$APPDIR/usr/bin" -executable -type f -print0) +fi + +if [ "$gtk_versions" -gt 1 ]; then + echo "$0: can not deploy multiple GTK versions at the same time." + echo "Please set DEPLOY_GTK_VERSION to {2, 3, 4}." + exit 1 +elif [ "$DEPLOY_GTK_VERSION" -eq 0 ]; then + echo "$0: failed to auto-detect GTK version." + echo "Please set DEPLOY_GTK_VERSION to {2, 3, 4}." + exit 1 +fi + +echo "Installing AppRun hook" +HOOKSDIR="$APPDIR/apprun-hooks" +HOOKFILE="$HOOKSDIR/linuxdeploy-plugin-gtk.sh" +mkdir -p "$HOOKSDIR" +cat > "$HOOKFILE" <<\EOF +#! /usr/bin/env bash + +gsettings get org.gnome.desktop.interface gtk-theme 2> /dev/null | grep -qi "dark" && GTK_THEME_VARIANT="dark" || GTK_THEME_VARIANT="light" +APPIMAGE_GTK_THEME="${APPIMAGE_GTK_THEME:-"Adwaita:$GTK_THEME_VARIANT"}" # Allow user to override theme (discouraged) + +export APPDIR="${APPDIR:-"$(dirname "$(realpath "$0")")"}" # Workaround to run extracted AppImage +export GTK_DATA_PREFIX="$APPDIR" +export GTK_THEME="$APPIMAGE_GTK_THEME" # Custom themes are broken +export GDK_BACKEND=x11 # Crash with Wayland backend on Wayland - We tested it without it and ended up with this: https://github.com/tauri-apps/tauri/issues/8541 +export XDG_DATA_DIRS="$APPDIR/usr/share:/usr/share:$XDG_DATA_DIRS" # g_get_system_data_dirs() from GLib +EOF + +echo "Installing GLib schemas" +# Note: schemasdir is undefined on Ubuntu 16.04 +glib_schemasdir="$(get_pkgconf_variable "schemasdir" "gio-2.0" "/usr/share/glib-2.0/schemas")" +copy_tree "$glib_schemasdir" "$APPDIR/" +glib-compile-schemas "$APPDIR/$glib_schemasdir" +cat >> "$HOOKFILE" <> "$HOOKFILE" < "$APPDIR/$gtk3_immodules_cache_file" + else + echo "WARNING: gtk-query-immodules-3.0 not found" + fi + if [ ! -f "$APPDIR/$gtk3_immodules_cache_file" ]; then + echo "WARNING: immodules.cache file is missing" + fi + sed -i "s|$gtk3_libdir/3.0.0/immodules/||g" "$APPDIR/$gtk3_immodules_cache_file" + ;; + 4) + echo "Installing GTK 4.0 modules" + gtk4_exec_prefix="$(get_pkgconf_variable "exec_prefix" "gtk4" "/usr")" + gtk4_libdir="$(get_pkgconf_variable "libdir" "gtk4")/gtk-4.0" + gtk4_path="$gtk4_libdir/modules" + copy_tree "$gtk4_libdir" "$APPDIR/" + cat >> "$HOOKFILE" <> "$HOOKFILE" < "$APPDIR/$gdk_pixbuf_cache_file" +else + echo "WARNING: gdk-pixbuf-query-loaders not found" +fi +if [ ! -f "$APPDIR/$gdk_pixbuf_cache_file" ]; then + echo "WARNING: loaders.cache file is missing" +fi +sed -i "s|$gdk_pixbuf_moduledir/||g" "$APPDIR/$gdk_pixbuf_cache_file" + +echo "Copying more libraries" +gobject_libdir="$(get_pkgconf_variable "libdir" "gobject-2.0")" +gio_libdir="$(get_pkgconf_variable "libdir" "gio-2.0")" +librsvg_libdir="$(get_pkgconf_variable "libdir" "librsvg-2.0")" +pango_libdir="$(get_pkgconf_variable "libdir" "pango")" +pangocairo_libdir="$(get_pkgconf_variable "libdir" "pangocairo")" +pangoft2_libdir="$(get_pkgconf_variable "libdir" "pangoft2")" +FIND_ARRAY=( + "$gdk_libdir" "libgdk_pixbuf-*.so*" + "$gobject_libdir" "libgobject-*.so*" + "$gio_libdir" "libgio-*.so*" + "$librsvg_libdir" "librsvg-*.so*" + "$pango_libdir" "libpango-*.so*" + "$pangocairo_libdir" "libpangocairo-*.so*" + "$pangoft2_libdir" "libpangoft2-*.so*" +) +LIBRARIES=() +for (( i=0; i<${#FIND_ARRAY[@]}; i+=2 )); do + directory=${FIND_ARRAY[i]} + library=${FIND_ARRAY[i+1]} + while IFS= read -r -d '' file; do + LIBRARIES+=( "--library=$file" ) + done < <(find "$directory" \( -type l -o -type f \) -name "$library" -print0) +done + +env LINUXDEPLOY_PLUGIN_MODE=1 "$LINUXDEPLOY" --appdir="$APPDIR" "${LIBRARIES[@]}" + +# Create symbolic links as a workaround +# Details: https://github.com/linuxdeploy/linuxdeploy-plugin-gtk/issues/24#issuecomment-1030026529 +echo "Manually setting rpath for GTK modules" +PATCH_ARRAY=( + "$gtk3_immodulesdir" + "$gtk3_printbackendsdir" + "$gdk_pixbuf_moduledir" +) +for directory in "${PATCH_ARRAY[@]}"; do + while IFS= read -r -d '' file; do + ln $verbose -s "${file/\/usr\/lib\//}" "$APPDIR/usr/lib" + done < <(find "$directory" -name '*.so' -print0) +done + +# set write permission on lib64 again to make it deletable. +chmod +w "$APPDIR"/usr/lib64 || true + +# We have to copy the files first to not get permission errors when we assign gio_extras_dir +find /usr/lib* -name libgiognutls.so -exec mkdir -p "$APPDIR"/"$(dirname '{}')" \; -exec cp --parents '{}' "$APPDIR/" \; || true +# related files that we seemingly don't need: +# libgiolibproxy.so - libgiognomeproxy.so - glib-pacrunner + +gio_extras_dir=$(find "$APPDIR"/usr/lib* -name libgiognutls.so -exec dirname '{}' \; 2>/dev/null) +cat >> "$HOOKFILE" < 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/macos/app.rs b/crates/tauri-bundler/src/bundle/macos/app.rs index cd7055f30..703973c2b 100644 --- a/crates/tauri-bundler/src/bundle/macos/app.rs +++ b/crates/tauri-bundler/src/bundle/macos/app.rs @@ -65,16 +65,12 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display()); if app_bundle_path.exists() { - fs::remove_dir_all(&app_bundle_path).fs_context( - "failed to remove old app bundle", - app_bundle_path.to_path_buf(), - )?; + fs::remove_dir_all(&app_bundle_path) + .fs_context("failed to remove old app bundle", &app_bundle_path)?; } let bundle_directory = app_bundle_path.join("Contents"); - fs::create_dir_all(&bundle_directory).fs_context( - "failed to create bundle directory", - bundle_directory.to_path_buf(), - )?; + fs::create_dir_all(&bundle_directory) + .fs_context("failed to create bundle directory", &bundle_directory)?; let resources_dir = bundle_directory.join("Resources"); let bin_dir = bundle_directory.join("MacOS"); @@ -459,20 +455,12 @@ fn copy_frameworks_to_bundle( ) -> crate::Result> { let mut paths = Vec::new(); - let frameworks = settings - .macos() - .frameworks - .as_ref() - .cloned() - .unwrap_or_default(); + let frameworks = settings.macos().frameworks.clone().unwrap_or_default(); if frameworks.is_empty() { return Ok(paths); } let dest_dir = bundle_directory.join("Frameworks"); - fs::create_dir_all(&dest_dir).fs_context( - "failed to create Frameworks directory", - dest_dir.to_path_buf(), - )?; + fs::create_dir_all(&dest_dir).fs_context("failed to create Frameworks directory", &dest_dir)?; for framework in frameworks.iter() { if framework.ends_with(".framework") { let src_path = PathBuf::from(framework); diff --git a/crates/tauri-bundler/src/bundle/macos/ios.rs b/crates/tauri-bundler/src/bundle/macos/ios.rs index e2a028113..ac035127a 100644 --- a/crates/tauri-bundler/src/bundle/macos/ios.rs +++ b/crates/tauri-bundler/src/bundle/macos/ios.rs @@ -44,15 +44,11 @@ pub fn bundle_project(settings: &Settings) -> crate::Result> { log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display()); if app_bundle_path.exists() { - fs::remove_dir_all(&app_bundle_path).fs_context( - "failed to remove old app bundle", - app_bundle_path.to_path_buf(), - )?; + fs::remove_dir_all(&app_bundle_path) + .fs_context("failed to remove old app bundle", &app_bundle_path)?; } - fs::create_dir_all(&app_bundle_path).fs_context( - "failed to create bundle directory", - app_bundle_path.to_path_buf(), - )?; + fs::create_dir_all(&app_bundle_path) + .fs_context("failed to create bundle directory", &app_bundle_path)?; for src in settings.resource_files() { let src = src?; diff --git a/crates/tauri-bundler/src/bundle/macos/sign.rs b/crates/tauri-bundler/src/bundle/macos/sign.rs index 8d8bf6c2b..acde62708 100644 --- a/crates/tauri-bundler/src/bundle/macos/sign.rs +++ b/crates/tauri-bundler/src/bundle/macos/sign.rs @@ -21,7 +21,7 @@ pub fn keychain(identity: Option<&str>) -> crate::Result>, - /// the list of of RPM dependencies your application recommends. + /// the list of RPM dependencies your application recommends. pub recommends: Option>, /// The list of RPM dependencies your application provides. pub provides: Option>, 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/msi/mod.rs b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs index cc5f83883..4c00d8f33 100644 --- a/crates/tauri-bundler/src/bundle/windows/msi/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/msi/mod.rs @@ -753,26 +753,28 @@ pub fn build_wix_app_installer( } let main_wxs_path = output_path.join("main.wxs"); - fs::write(main_wxs_path, handlebars.render("main.wxs", &data)?)?; + fs::write(&main_wxs_path, handlebars.render("main.wxs", &data)?)?; - let mut candle_inputs = vec![("main.wxs".into(), Vec::new())]; + let mut candle_inputs = vec![]; let current_dir = std::env::current_dir()?; let extension_regex = Regex::new("\"http://schemas.microsoft.com/wix/(\\w+)\"")?; - for fragment_path in fragment_paths { - let fragment_path = current_dir.join(fragment_path); - let fragment_content = fs::read_to_string(&fragment_path)?; - let fragment_handlebars = Handlebars::new(); - let fragment = fragment_handlebars.render_template(&fragment_content, &data)?; + let input_paths = + std::iter::once(main_wxs_path).chain(fragment_paths.iter().map(|p| current_dir.join(p))); + + for input_path in input_paths { + let input_content = fs::read_to_string(&input_path)?; + let input_handlebars = Handlebars::new(); + let input = input_handlebars.render_template(&input_content, &data)?; let mut extensions = Vec::new(); - for cap in extension_regex.captures_iter(&fragment) { + for cap in extension_regex.captures_iter(&input) { let path = wix_toolset_path.join(format!("Wix{}.dll", &cap[1])); if settings.windows().can_sign() { try_sign(&path, settings)?; } extensions.push(path); } - candle_inputs.push((fragment_path, extensions)); + candle_inputs.push((input_path, extensions)); } let mut fragment_extensions = HashSet::new(); 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 d1729c82f..5b7479a84 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs +++ b/crates/tauri-bundler/src/bundle/windows/nsis/mod.rs @@ -36,12 +36,12 @@ use std::{ // URLS for the NSIS toolchain. #[cfg(target_os = "windows")] const NSIS_URL: &str = - "https://github.com/tauri-apps/binary-releases/releases/download/nsis-3/nsis-3.zip"; + "https://github.com/tauri-apps/binary-releases/releases/download/nsis-3.11/nsis-3.11.zip"; #[cfg(target_os = "windows")] -const NSIS_SHA1: &str = "057e83c7d82462ec394af76c87d06733605543d4"; +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.1/nsis_tauri_utils.dll"; -const NSIS_TAURI_UTILS_SHA1: &str = "B053B2E5FDB97257954C8F935D80964F056520AE"; + "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] = &[ @@ -55,6 +55,9 @@ const NSIS_REQUIRED_FILES: &[&str] = &[ "Include/x64.nsh", "Include/nsDialogs.nsh", "Include/WinMessages.nsh", + "Include/Win/COM.nsh", + "Include/Win/Propkey.nsh", + "Include/Win/RestartManager.nsh", ]; const NSIS_PLUGIN_FILES: &[&str] = &[ "NSISdl.dll", @@ -125,7 +128,7 @@ fn get_and_extract_nsis(nsis_toolset_path: &Path, _tauri_tools_path: &Path) -> c let data = download_and_verify(NSIS_URL, NSIS_SHA1, HashAlgorithm::Sha1)?; log::info!("extracting NSIS"); crate::utils::http_utils::extract_zip(&data, _tauri_tools_path)?; - fs::rename(_tauri_tools_path.join("nsis-3.08"), nsis_toolset_path)?; + fs::rename(_tauri_tools_path.join("nsis-3.11"), nsis_toolset_path)?; } // download additional plugins @@ -295,8 +298,12 @@ fn build_nsis_app_installer( data.insert("copyright", to_json(settings.copyright_string())); if settings.windows().can_sign() { - let sign_cmd = format!("{:?}", sign_command("%1", &settings.sign_params())?); - data.insert("uninstaller_sign_cmd", to_json(sign_cmd)); + if settings.no_sign() { + log::warn!("Skipping signing for NSIS uninstaller due to --no-sign flag."); + } else { + let sign_cmd = format!("{:?}", sign_command("%1", &settings.sign_params())?); + data.insert("uninstaller_sign_cmd", to_json(sign_cmd)); + } } let version = settings.version_string(); @@ -614,13 +621,16 @@ fn build_nsis_app_installer( fs::create_dir_all(nsis_installer_path.parent().unwrap())?; if settings.windows().can_sign() { - log::info!("Signing NSIS plugins"); - for dll in NSIS_PLUGIN_FILES { - let path = additional_plugins_path.join(dll); - if path.exists() { - try_sign(&path, settings)?; - } else { - log::warn!("Could not find {}, skipping signing", path.display()); + if let Some(plugin_copy_path) = &maybe_plugin_copy_path { + let plugin_copy_path = plugin_copy_path.join("x86-unicode"); + log::info!("Signing NSIS plugins"); + for dll in NSIS_PLUGIN_FILES { + let path = plugin_copy_path.join(dll); + if path.exists() { + try_sign(&path, settings)?; + } else { + log::warn!("Could not find {}, skipping signing", path.display()); + } } } } @@ -857,6 +867,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/nsis/utils.nsh b/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh index 88b82b0f8..3c5bf75f5 100644 --- a/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh +++ b/crates/tauri-bundler/src/bundle/windows/nsis/utils.nsh @@ -48,6 +48,7 @@ Pop $R0 Sleep 500 ${If} $R0 = 0 + ${OrIf} $R0 = 2 Goto app_check_done_${UniqueID} ${Else} IfSilent silent_${UniqueID} ui_${UniqueID} diff --git a/crates/tauri-bundler/src/bundle/windows/sign.rs b/crates/tauri-bundler/src/bundle/windows/sign.rs index 04e5a2da5..f7c7ad1e2 100644 --- a/crates/tauri-bundler/src/bundle/windows/sign.rs +++ b/crates/tauri-bundler/src/bundle/windows/sign.rs @@ -266,8 +266,7 @@ pub fn try_sign>(file_path: P, settings: &Settings) -> crate::Res pub fn should_sign(file_path: &Path) -> crate::Result { let is_binary = file_path .extension() - .and_then(|extension| extension.to_str()) - .is_some_and(|extension| matches!(extension, "exe" | "dll")); + .is_some_and(|ext| ext == "exe" || ext == "dll"); if !is_binary { return Ok(false); } 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 3a8fe82dd..40547a3ee 100644 --- a/crates/tauri-bundler/src/error.rs +++ b/crates/tauri-bundler/src/error.rs @@ -105,6 +105,7 @@ pub enum Error { #[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-bundler/src/utils/http_utils.rs b/crates/tauri-bundler/src/utils/http_utils.rs index bbabb8544..62ade96cb 100644 --- a/crates/tauri-bundler/src/utils/http_utils.rs +++ b/crates/tauri-bundler/src/utils/http_utils.rs @@ -14,6 +14,8 @@ use sha2::Digest; use url::Url; use zip::ZipArchive; +const BUNDLER_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); + fn generate_github_mirror_url_from_template(github_url: &str) -> Option { std::env::var("TAURI_BUNDLER_TOOLS_GITHUB_MIRROR_TEMPLATE") .ok() @@ -47,7 +49,15 @@ fn generate_github_alternative_url(url: &str) -> Option<(ureq::Agent, String)> { generate_github_mirror_url_from_template(url) .or_else(|| generate_github_mirror_url_from_base(url)) - .map(|alt_url| (ureq::agent(), alt_url)) + .map(|alt_url| { + ( + ureq::Agent::config_builder() + .user_agent(BUNDLER_USER_AGENT) + .build() + .into(), + alt_url, + ) + }) } fn create_agent_and_url(url: &str) -> (ureq::Agent, String) { @@ -55,22 +65,21 @@ fn create_agent_and_url(url: &str) -> (ureq::Agent, String) { } pub(crate) fn base_ureq_agent() -> ureq::Agent { + #[allow(unused_mut)] + let mut config_builder = ureq::Agent::config_builder() + .user_agent(BUNDLER_USER_AGENT) + .proxy(ureq::Proxy::try_from_env()); + #[cfg(feature = "platform-certs")] - let agent: ureq::Agent = ureq::Agent::config_builder() - .tls_config( + { + config_builder = config_builder.tls_config( ureq::tls::TlsConfig::builder() .root_certs(ureq::tls::RootCerts::PlatformVerifier) .build(), - ) - .proxy(ureq::Proxy::try_from_env()) - .build() - .into(); - #[cfg(not(feature = "platform-certs"))] - let agent: ureq::Agent = ureq::Agent::config_builder() - .proxy(ureq::Proxy::try_from_env()) - .build() - .into(); - agent + ); + } + + config_builder.build().into() } #[allow(dead_code)] diff --git a/crates/tauri-cli/CHANGELOG.md b/crates/tauri-cli/CHANGELOG.md index 5d539f82a..cb3bc6716 100644 --- a/crates/tauri-cli/CHANGELOG.md +++ b/crates/tauri-cli/CHANGELOG.md @@ -1,5 +1,108 @@ # Changelog +## \[2.9.6] + +### What's Changed + +- [`7b1b3514d`](https://www.github.com/tauri-apps/tauri/commit/7b1b3514df771e6e9859b9f54fa4df332433948e) ([#14621](https://www.github.com/tauri-apps/tauri/pull/14621) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Errors like `Error Failed to parse version 2 for for NPM package tauri` when there was no `package-lock.json` file present yet or when using ones like `link:./tauri` are now only logged in `--verbose` mode. + +### Dependencies + +- Upgraded to `tauri-macos-sign@2.3.2` +- Upgraded to `tauri-bundler@2.7.5` + +## \[2.9.5] + +### Bug Fixes + +- [`f022b2d1a`](https://www.github.com/tauri-apps/tauri/commit/f022b2d1ae57612e39c75782926f2f341d9034a8) ([#14582](https://www.github.com/tauri-apps/tauri/pull/14582) by [@hrzlgnm](https://www.github.com/tauri-apps/tauri/../../hrzlgnm)) Fixed an issue that caused the cli to error out with missing private key, in case the option `--no-sign` was requested and the `tauri.config` has signing key set and the plugin `tauri-plugin-updater` is used. +- [`f855caf8a`](https://www.github.com/tauri-apps/tauri/commit/f855caf8a3830aa5dd6d0b039312866a5d9c3606) ([#14481](https://www.github.com/tauri-apps/tauri/pull/14481) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fixed the mismatched tauri package versions check didn't work for pnpm +- [`79a7d9ec0`](https://www.github.com/tauri-apps/tauri/commit/79a7d9ec01be1a371b8e923848140fea75e9caed) ([#14468](https://www.github.com/tauri-apps/tauri/pull/14468) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused the cli to print errors like `Error Failed to parse version 2 for crate tauri` when there was no `Cargo.lock` file present yet. This will still be logged in `--verbose` mode. + +### Performance Improvements + +- [`ce98d87ce`](https://www.github.com/tauri-apps/tauri/commit/ce98d87ce0aaa907285852eb80691197424e03c3) ([#14474](https://www.github.com/tauri-apps/tauri/pull/14474) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) refactor: remove needless collect. No user facing changes. +- [`ee3cc4a91`](https://www.github.com/tauri-apps/tauri/commit/ee3cc4a91bf1315ecaefe90f423ffd55ef6c40db) ([#14475](https://www.github.com/tauri-apps/tauri/pull/14475) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) perf: remove needless clones in various files for improved performance. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-bundler@2.7.4` +- Upgraded to `tauri-macos-sign@2.3.1` +- Upgraded to `tauri-utils@2.8.1` + +## \[2.9.4] + +### Bug Fixes + +- [`b586ecf1f`](https://www.github.com/tauri-apps/tauri/commit/b586ecf1f4b3b087f9aa6c4668c2c18b1b7925f4) ([#14416](https://www.github.com/tauri-apps/tauri/pull/14416) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Premultiply Alpha before Resizing which gets rid of the gray fringe around the icons for svg images. + +## \[2.9.3] + +### Enhancements + +- [`22edc65aa`](https://www.github.com/tauri-apps/tauri/commit/22edc65aad0b3e45515008e8e0866112da70c8a1) ([#14408](https://www.github.com/tauri-apps/tauri/pull/14408) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Set user-agent in bundler and cli http requests when fetching build tools. +- [`779612ac8`](https://www.github.com/tauri-apps/tauri/commit/779612ac8425a787626da4cefdb9eaf7d63bea18) ([#14379](https://www.github.com/tauri-apps/tauri/pull/14379) by [@moubctez](https://www.github.com/tauri-apps/tauri/../../moubctez)) Properly read the `required-features` field of binaries in Cargo.toml to prevent bundling issues when the features weren't enabled. + +### Bug Fixes + +- [`fd8c30b4f`](https://www.github.com/tauri-apps/tauri/commit/fd8c30b4f1bca8dd7165c5c0ebe7fbfd17662153) ([#14353](https://www.github.com/tauri-apps/tauri/pull/14353) by [@ChaseKnowlden](https://www.github.com/tauri-apps/tauri/../../ChaseKnowlden)) Premultiply Alpha before Resizing which gets rid of the gray fringe around the icons. + +### Dependencies + +- Upgraded to `tauri-bundler@2.7.3` + +## \[2.9.2] + +### Dependencies + +- Upgraded to `tauri-bundler@2.7.2` + +## \[2.9.1] + +### Dependencies + +- Upgraded to `tauri-macos-sign@2.3.0` +- Upgraded to `tauri-bundler@2.7.1` + +## \[2.9.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scrollBarStyle` option to the window configuration. +- [`2a06d1006`](https://www.github.com/tauri-apps/tauri/commit/2a06d10066a806e392efe8bfb16d943ee0b0b61d) ([#14052](https://www.github.com/tauri-apps/tauri/pull/14052)) Add a `--no-sign` flag to the `tauri build` and `tauri bundle` commands to skip the code signing step, improving the developer experience for local testing and development without requiring code signing keys. +- [`3b4fac201`](https://www.github.com/tauri-apps/tauri/commit/3b4fac2017832d426dd07c5e24e26684eda57f7b) ([#14194](https://www.github.com/tauri-apps/tauri/pull/14194)) Add `tauri.conf.json > bundle > android > autoIncrementVersionCode` config option to automatically increment the Android version code. +- [`673867aa0`](https://www.github.com/tauri-apps/tauri/commit/673867aa0e1ccd766ee879ffe96aba58c758613c) ([#14094](https://www.github.com/tauri-apps/tauri/pull/14094)) Try to detect ANDROID_HOME and NDK_HOME environment variables from default system locations and install them if needed using the Android Studio command line tools. +- [`3d6868d09`](https://www.github.com/tauri-apps/tauri/commit/3d6868d09c323d68a152f3c3f8c7256311bd020a) ([#14128](https://www.github.com/tauri-apps/tauri/pull/14128)) Added support to defining the content type of the declared file association on macOS (maps to LSItemContentTypes property). +- [`3d6868d09`](https://www.github.com/tauri-apps/tauri/commit/3d6868d09c323d68a152f3c3f8c7256311bd020a) ([#14128](https://www.github.com/tauri-apps/tauri/pull/14128)) Added support to defining the metadata for custom types declared in `tauri.conf.json > bundle > fileAssociations > exportedType` via the `UTExportedTypeDeclarations` Info.plist property. +- [`ed7c9a410`](https://www.github.com/tauri-apps/tauri/commit/ed7c9a4100e08c002212265549d12130d021ad1e) ([#14108](https://www.github.com/tauri-apps/tauri/pull/14108)) Added `bundle > macOS > infoPlist` and `bundle > iOS > infoPlist` configurations to allow defining custom Info.plist extensions. +- [`75082cc5b`](https://www.github.com/tauri-apps/tauri/commit/75082cc5b340e30e2c4b4cd4bd6a1fe5382164aa) ([#14120](https://www.github.com/tauri-apps/tauri/pull/14120)) Added `ios run` and `android run` commands to run the app in production mode. +- [`cc8c0b531`](https://www.github.com/tauri-apps/tauri/commit/cc8c0b53171173dbd1d01781a50de1a3ea159031) ([#14031](https://www.github.com/tauri-apps/tauri/pull/14031)) Added support to universal app links on macOS with the `plugins > deep-link > desktop > domains` configuration. + +### Enhancements + +- [`94cbd40fc`](https://www.github.com/tauri-apps/tauri/commit/94cbd40fc733e08c0bccd48149d22a0e9c2f1e5c) ([#14223](https://www.github.com/tauri-apps/tauri/pull/14223)) Add support for Android's adaptive and themed icons. +- [`b5aa01870`](https://www.github.com/tauri-apps/tauri/commit/b5aa018702bf45dc98297698f9b7d238705865a6) ([#14268](https://www.github.com/tauri-apps/tauri/pull/14268)) Update cargo-mobile2 to 0.21, enhancing error messages and opening Xcode when multiple apps are installed. +- [`55453e845`](https://www.github.com/tauri-apps/tauri/commit/55453e8453d927b8197f1ba9f26fd944482938f7) ([#14262](https://www.github.com/tauri-apps/tauri/pull/14262)) Check mismatched versions in `tauri info` +- [`1a6627ee7`](https://www.github.com/tauri-apps/tauri/commit/1a6627ee7d085a4e66784e2705254714d68c7244) ([#14122](https://www.github.com/tauri-apps/tauri/pull/14122)) Set a default log level filter when running `tauri add log`. +- [`b06b3bd09`](https://www.github.com/tauri-apps/tauri/commit/b06b3bd091b0fed26cdcfb23cacb0462a7a9cc2d) ([#14126](https://www.github.com/tauri-apps/tauri/pull/14126)) Improve error messages with more context. +- [`f6622a3e3`](https://www.github.com/tauri-apps/tauri/commit/f6622a3e342f5dd5fb3cf6e0f79fb309a10e9b3d) ([#14129](https://www.github.com/tauri-apps/tauri/pull/14129)) Prompt to install the iOS platform if it isn't installed yet. +- [`6bbb530fd`](https://www.github.com/tauri-apps/tauri/commit/6bbb530fd5edfc07b180a4f3782b8566872ca3b1) ([#14105](https://www.github.com/tauri-apps/tauri/pull/14105)) Warn if productName is empty when initializing mobile project. + +### Bug Fixes + +- [`19fb6f7cb`](https://www.github.com/tauri-apps/tauri/commit/19fb6f7cb0d702cb2f25f6f2d1e11014d9dada5d) ([#14146](https://www.github.com/tauri-apps/tauri/pull/14146)) Strip Windows-only extensions from the binary path so an Android project initialized on Windows can be used on UNIX systems. +- [`19fb6f7cb`](https://www.github.com/tauri-apps/tauri/commit/19fb6f7cb0d702cb2f25f6f2d1e11014d9dada5d) ([#14146](https://www.github.com/tauri-apps/tauri/pull/14146)) Enhance Android build script usage on Windows by attempting to run cmd, bat and exe formats. +- [`28a2f9bc5`](https://www.github.com/tauri-apps/tauri/commit/28a2f9bc55f658eb71ef1a970ff9f791346f7682) ([#14101](https://www.github.com/tauri-apps/tauri/pull/14101)) Fix iOS CLI usage after modifying the package name. +- [`d2938486e`](https://www.github.com/tauri-apps/tauri/commit/d2938486e9d974debd90c15d7160b8a17bf4d763) ([#14261](https://www.github.com/tauri-apps/tauri/pull/14261)) Replaced the non-standard nerd font character with ` ⱼₛ ` in `tarui info` +- [`25e920e16`](https://www.github.com/tauri-apps/tauri/commit/25e920e169db900ca4f07c2bb9eb290e9f9f2c7d) ([#14298](https://www.github.com/tauri-apps/tauri/pull/14298)) Wait for dev server to exit before exiting the CLI when the app is closed on `tauri dev --no-watch`. +- [`b0012424c`](https://www.github.com/tauri-apps/tauri/commit/b0012424c5f432debfa42ba145e2672966d5f6d5) ([#14115](https://www.github.com/tauri-apps/tauri/pull/14115)) Resolve local IP address when `tauri.conf.json > build > devUrl` host is `0.0.0.0`. +- [`abf7e8850`](https://www.github.com/tauri-apps/tauri/commit/abf7e8850ba41e7173e9e9a3fdd6dfb8f357d72d) ([#14118](https://www.github.com/tauri-apps/tauri/pull/14118)) Fixes mobile project initialization when using `pnpx` or `pnpm dlx`. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- Upgraded to `tauri-bundler@2.7.0` + ## \[2.8.4] ### Enhancements diff --git a/crates/tauri-cli/Cargo.toml b/crates/tauri-cli/Cargo.toml index b8bf475c4..131b654a7 100644 --- a/crates/tauri-cli/Cargo.toml +++ b/crates/tauri-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-cli" -version = "2.8.4" +version = "2.9.6" authors = ["Tauri Programme within The Commons Conservancy"] edition = "2021" rust-version = "1.77.2" @@ -36,7 +36,7 @@ name = "cargo-tauri" path = "src/main.rs" [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\", target_os = \"windows\", target_os = \"macos\"))".dependencies] -cargo-mobile2 = { version = "0.20.6", default-features = false } +cargo-mobile2 = { version = "0.21.1", default-features = false } [dependencies] jsonrpsee = { version = "0.24", features = ["server"] } @@ -47,7 +47,7 @@ sublime_fuzzy = "0.7" clap_complete = "4" clap = { version = "4", features = ["derive", "env"] } thiserror = "2" -tauri-bundler = { version = "2.6.1", default-features = false, path = "../tauri-bundler" } +tauri-bundler = { version = "2.7.5", default-features = false, path = "../tauri-bundler" } colored = "2" serde = { version = "1", features = ["derive"] } serde_json = { version = "1", features = ["preserve_order"] } @@ -56,9 +56,9 @@ notify = "8" notify-debouncer-full = "0.6" shared_child = "1" duct = "1.0" -toml_edit = { version = "0.23", features = ["serde"] } +toml_edit = { version = "0.24", features = ["serde"] } json-patch = "3" -tauri-utils = { version = "2.7.0", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [ "isolation", "schema", "config-json5", @@ -66,11 +66,11 @@ tauri-utils = { version = "2.7.0", path = "../tauri-utils", features = [ "html-manipulation", ] } toml = "0.9" -jsonschema = "0.33" +jsonschema = { version = "0.33", default-features = false } handlebars = "6" include_dir = "0.7" dirs = "6" -minisign = "=0.7.3" +minisign = "0.8" base64 = "0.22" ureq = { version = "3", default-features = false, features = ["gzip"] } os_info = "3" @@ -113,6 +113,7 @@ uuid = { version = "1", features = ["v5"] } rand = "0.9" zip = { version = "4", default-features = false, features = ["deflate"] } which = "8" +rayon = "1.10" [dev-dependencies] insta = "1" @@ -132,7 +133,7 @@ libc = "0.2" [target."cfg(target_os = \"macos\")".dependencies] plist = "1" -tauri-macos-sign = { version = "2.2.0", path = "../tauri-macos-sign" } +tauri-macos-sign = { version = "2.3.2", path = "../tauri-macos-sign" } object = { version = "0.36", default-features = false, features = [ "macho", "read_core", diff --git a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md index 40173018f..5a8a18100 100644 --- a/crates/tauri-cli/ENVIRONMENT_VARIABLES.md +++ b/crates/tauri-cli/ENVIRONMENT_VARIABLES.md @@ -33,7 +33,7 @@ These environment variables are inputs to the CLI which may have an equivalent C - See [creating API keys](https://developer.apple.com/documentation/appstoreconnectapi/creating_api_keys_for_app_store_connect_api) for more information. - `API_PRIVATE_KEYS_DIR` — Specify the directory where your AuthKey file is located. See `APPLE_API_KEY`. - `APPLE_API_ISSUER` — Issuer ID. Required if `APPLE_API_KEY` is specified. -- `APPLE_API_KEY_PATH` - path to the API key `.p8` file. If not specified, for macOS apps the bundler searches the following directories in sequence for a private key file with the name of 'AuthKey\_.p8': './private_keys', '~/private_keys', '~/.private_keys', and '~/.appstoreconnect/private_keys'. **For iOS this variable is required**. +- `APPLE_API_KEY_PATH` - path to the API key `.p8` file. If not specified, for macOS apps the bundler searches the following directories in sequence for a private key file with the name of `AuthKey\_.p8`: `./private_keys`, `~/private_keys`, `~/.private_keys`, and `~/.appstoreconnect/private_keys`. **For iOS this variable is required**. - `APPLE_SIGNING_IDENTITY` — The identity used to code sign. Overwrites `tauri.conf.json > bundle > macOS > signingIdentity`. If neither are set, it is inferred from `APPLE_CERTIFICATE` when provided. - `APPLE_PROVIDER_SHORT_NAME` — If your Apple ID is connected to multiple teams, you have to specify the provider short name of the team you want to use to notarize your app. Overwrites `tauri.conf.json > bundle > macOS > providerShortName`. - `APPLE_DEVELOPMENT_TEAM` — The team ID used to code sign on iOS. Overwrites `tauri.conf.json > bundle > iOS > developmentTeam`. Can be found in https://developer.apple.com/account#MembershipDetailsCard. diff --git a/crates/tauri-cli/config.schema.json b/crates/tauri-cli/config.schema.json index 6f8593965..ffc72c24e 100644 --- a/crates/tauri-cli/config.schema.json +++ b/crates/tauri-cli/config.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://schema.tauri.app/config/2.8.5", + "$id": "https://schema.tauri.app/config/2.9.5", "title": "Config", "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"http://localhost:3000\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", "type": "object", @@ -84,6 +84,7 @@ "default": { "active": false, "android": { + "autoIncrementVersionCode": false, "minSdkVersion": 24 }, "createUpdaterArtifacts": false, @@ -167,7 +168,7 @@ "type": "object", "properties": { "windows": { - "description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", + "description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", "default": [], "type": "array", "items": { @@ -233,7 +234,7 @@ "type": "string" }, "create": { - "description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).\n\n ## Example:\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", + "description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).\n\n ## Example:\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", "default": true, "type": "boolean" }, @@ -264,7 +265,7 @@ "type": "boolean" }, "x": { - "description": "The horizontal position of the window's top left corner", + "description": "The horizontal position of the window's top left corner in logical pixels", "type": [ "number", "null" @@ -272,7 +273,7 @@ "format": "double" }, "y": { - "description": "The vertical position of the window's top left corner", + "description": "The vertical position of the window's top left corner in logical pixels", "type": [ "number", "null" @@ -280,19 +281,19 @@ "format": "double" }, "width": { - "description": "The window width.", + "description": "The window width in logical pixels.", "default": 800.0, "type": "number", "format": "double" }, "height": { - "description": "The window height.", + "description": "The window height in logical pixels.", "default": 600.0, "type": "number", "format": "double" }, "minWidth": { - "description": "The min window width.", + "description": "The min window width in logical pixels.", "type": [ "number", "null" @@ -300,7 +301,7 @@ "format": "double" }, "minHeight": { - "description": "The min window height.", + "description": "The min window height in logical pixels.", "type": [ "number", "null" @@ -308,7 +309,7 @@ "format": "double" }, "maxWidth": { - "description": "The max window width.", + "description": "The max window width in logical pixels.", "type": [ "number", "null" @@ -316,7 +317,7 @@ "format": "double" }, "maxHeight": { - "description": "The max window height.", + "description": "The max window height in logical pixels.", "type": [ "number", "null" @@ -654,13 +655,13 @@ ], "properties": { "width": { - "description": "Horizontal margin in physical unit", + "description": "Horizontal margin in physical pixels", "type": "integer", "format": "uint32", "minimum": 0.0 }, "height": { - "description": "Vertical margin in physical unit", + "description": "Vertical margin in physical pixels", "type": "integer", "format": "uint32", "minimum": 0.0 @@ -923,7 +924,7 @@ ] }, { - "description": "Mica effect that matches the system dark perefence **Windows 11 Only**", + "description": "Mica effect that matches the system dark preference **Windows 11 Only**", "type": "string", "enum": [ "mica" @@ -944,7 +945,7 @@ ] }, { - "description": "Tabbed effect that matches the system dark perefence **Windows 11 Only**", + "description": "Tabbed effect that matches the system dark preference **Windows 11 Only**", "type": "string", "enum": [ "tabbed" @@ -1298,7 +1299,7 @@ "additionalProperties": false }, "FsScope": { - "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,\n `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$TEMP`,\n `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", "anyOf": [ { "description": "A list of paths that are allowed by this scope.", @@ -1993,7 +1994,7 @@ "description": "Defines the URL or assets to embed in the application.", "anyOf": [ { - "description": "An external URL that should be used as the default application URL.", + "description": "An external URL that should be used as the default application URL. No assets are embedded in the app in this case.", "type": "string", "format": "uri" }, @@ -2002,7 +2003,7 @@ "type": "string" }, { - "description": "An array of files to embed on the app.", + "description": "An array of files to embed in the app.", "type": "array", "items": { "type": "string" @@ -2288,6 +2289,7 @@ "android": { "description": "Android configuration.", "default": { + "autoIncrementVersionCode": false, "minSdkVersion": 24 }, "allOf": [ @@ -2796,7 +2798,7 @@ "type": "object", "properties": { "version": { - "description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and foruth fields have a maximum value of 65,535.\n\n See for more info.", + "description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and fourth fields have a maximum value of 65,535.\n\n See for more info.", "type": [ "string", "null" @@ -3100,7 +3102,7 @@ "description": "Custom Signing Command configuration.", "anyOf": [ { - "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].", + "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::CommandWithOptions`].", "type": "string" }, { @@ -3853,6 +3855,11 @@ "format": "uint32", "maximum": 2100000000.0, "minimum": 1.0 + }, + "autoIncrementVersionCode": { + "description": "Whether to automatically increment the `versionCode` on each build.\n\n - If `true`, the generator will try to read the last `versionCode` from\n `tauri.properties` and increment it by 1 for every build.\n - If `false` or not set, it falls back to `version_code` or semver-derived logic.\n\n Note that to use this feature, you should remove `/tauri.properties` from `src-tauri/gen/android/app/.gitignore` so the current versionCode is committed to the repository.", + "default": false, + "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-cli/metadata-v2.json b/crates/tauri-cli/metadata-v2.json index e68c243f6..510949b94 100644 --- a/crates/tauri-cli/metadata-v2.json +++ b/crates/tauri-cli/metadata-v2.json @@ -1,9 +1,9 @@ { "cli.js": { - "version": "2.8.4", + "version": "2.9.6", "node": ">= 10.0.0" }, - "tauri": "2.8.5", - "tauri-build": "2.4.1", - "tauri-plugin": "2.4.0" + "tauri": "2.9.5", + "tauri-build": "2.5.3", + "tauri-plugin": "2.5.2" } diff --git a/crates/tauri-cli/src/acl/capability/new.rs b/crates/tauri-cli/src/acl/capability/new.rs index aceddc05d..14324be18 100644 --- a/crates/tauri-cli/src/acl/capability/new.rs +++ b/crates/tauri-cli/src/acl/capability/new.rs @@ -7,12 +7,7 @@ use std::{collections::HashSet, path::PathBuf}; use clap::Parser; use tauri_utils::acl::capability::{Capability, PermissionEntry}; -use crate::{ - acl::FileFormat, - error::ErrorExt, - helpers::{app_paths::tauri_dir, prompts}, - Result, -}; +use crate::{acl::FileFormat, error::ErrorExt, helpers::prompts, Result}; #[derive(Debug, Parser)] #[clap(about = "Create a new permission file")] @@ -37,7 +32,7 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); let identifier = match options.identifier { Some(i) => i, @@ -111,8 +106,7 @@ pub fn command(options: Options) -> Result<()> { .canonicalize() .fs_context("failed to canonicalize capability file path", o.clone())?, None => { - let dir = tauri_dir(); - let capabilities_dir = dir.join("capabilities"); + let capabilities_dir = dirs.tauri.join("capabilities"); capabilities_dir.join(format!( "{}.{}", capability.identifier, diff --git a/crates/tauri-cli/src/acl/permission/ls.rs b/crates/tauri-cli/src/acl/permission/ls.rs index 7cb7c3d1b..ccebfebf0 100644 --- a/crates/tauri-cli/src/acl/permission/ls.rs +++ b/crates/tauri-cli/src/acl/permission/ls.rs @@ -6,7 +6,6 @@ use clap::Parser; use crate::{ error::{Context, ErrorExt}, - helpers::app_paths::tauri_dir, Result, }; use colored::Colorize; @@ -25,16 +24,17 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); - let acl_manifests_path = tauri_dir() + let acl_manifests_path = dirs + .tauri .join("gen") .join("schemas") .join("acl-manifests.json"); if acl_manifests_path.exists() { let plugin_manifest_json = read_to_string(&acl_manifests_path) - .fs_context("failed to read plugin manifest", acl_manifests_path.clone())?; + .fs_context("failed to read plugin manifest", acl_manifests_path)?; let acl = serde_json::from_str::>(&plugin_manifest_json) .context("failed to parse plugin manifest as JSON")?; diff --git a/crates/tauri-cli/src/add.rs b/crates/tauri-cli/src/add.rs index 8a45c0880..074b0e3b2 100644 --- a/crates/tauri-cli/src/add.rs +++ b/crates/tauri-cli/src/add.rs @@ -10,7 +10,7 @@ use crate::{ acl, error::ErrorExt, helpers::{ - app_paths::{resolve_frontend_dir, tauri_dir}, + app_paths::{resolve_frontend_dir, Dirs}, cargo, npm::PackageManager, }, @@ -39,11 +39,11 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); - run(options) + let dirs = crate::helpers::app_paths::resolve_dirs(); + run(options, &dirs) } -pub fn run(options: Options) -> Result<()> { +pub fn run(options: Options, dirs: &Dirs) -> Result<()> { let (plugin, version) = options .plugin .split_once('@') @@ -71,7 +71,6 @@ pub fn run(options: Options) -> Result<()> { } let frontend_dir = resolve_frontend_dir(); - let tauri_dir = tauri_dir(); let target_str = metadata .desktop_only @@ -90,7 +89,7 @@ pub fn run(options: Options) -> Result<()> { branch: options.branch.as_deref(), rev: options.rev.as_deref(), tag: options.tag.as_deref(), - cwd: Some(tauri_dir), + cwd: Some(dirs.tauri), target: target_str, })?; @@ -117,7 +116,7 @@ pub fn run(options: Options) -> Result<()> { (None, None, None, None) => npm_name, _ => crate::error::bail!("Only one of --tag, --rev and --branch can be specified"), }; - manager.install(&[npm_spec], tauri_dir)?; + manager.install(&[npm_spec], dirs.tauri)?; } let _ = acl::permission::add::command(acl::permission::add::Options { @@ -143,7 +142,10 @@ pub fn run(options: Options) -> Result<()> { let plugin_init = format!(".plugin(tauri_plugin_{plugin_snake_case}::{plugin_init_fn})"); let re = Regex::new(r"(tauri\s*::\s*Builder\s*::\s*default\(\))(\s*)").unwrap(); - for file in [tauri_dir.join("src/main.rs"), tauri_dir.join("src/lib.rs")] { + for file in [ + dirs.tauri.join("src/main.rs"), + dirs.tauri.join("src/lib.rs"), + ] { let contents = std::fs::read_to_string(&file).fs_context("failed to read Rust entry point", file.clone())?; @@ -166,7 +168,7 @@ pub fn run(options: Options) -> Result<()> { log::info!("Running `cargo fmt`..."); let _ = Command::new("cargo") .arg("fmt") - .current_dir(tauri_dir) + .current_dir(dirs.tauri) .status(); } diff --git a/crates/tauri-cli/src/build.rs b/crates/tauri-cli/src/build.rs index 12accb16f..b43b3c9ae 100644 --- a/crates/tauri-cli/src/build.rs +++ b/crates/tauri-cli/src/build.rs @@ -7,8 +7,8 @@ use crate::{ error::{Context, ErrorExt}, helpers::{ self, - app_paths::{frontend_dir, tauri_dir}, - config::{get as get_config, ConfigHandle, FrontendDist}, + app_paths::Dirs, + config::{get_config, ConfigMetadata, FrontendDist}, }, info::plugins::check_mismatched_packages, interface::{rust::get_cargo_target_dir, AppInterface, Interface}, @@ -40,7 +40,7 @@ pub struct Options { pub target: Option, /// Space or comma separated list of features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// Space or comma separated list of bundles to package. #[clap(short, long, action = ArgAction::Append, num_args(0..), value_delimiter = ',')] pub bundles: Option>, @@ -82,7 +82,7 @@ pub struct Options { } pub fn command(mut options: Options, verbosity: u8) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); if options.no_sign { log::warn!("--no-sign flag detected: Signing will be skipped."); @@ -99,41 +99,37 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { let config = get_config( target, &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, )?; - let mut interface = AppInterface::new( - config.lock().unwrap().as_ref().unwrap(), - options.target.clone(), - )?; + let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?; - setup(&interface, &mut options, config.clone(), false)?; + setup(&interface, &mut options, &config, &dirs, false)?; - let config_guard = config.lock().unwrap(); - let config_ = config_guard.as_ref().unwrap(); - - if let Some(minimum_system_version) = &config_.bundle.macos.minimum_system_version { + if let Some(minimum_system_version) = &config.bundle.macos.minimum_system_version { std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version); } let app_settings = interface.app_settings(); let interface_options = options.clone().into(); - let out_dir = app_settings.out_dir(&interface_options)?; + let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?; - let bin_path = interface.build(interface_options)?; + let bin_path = interface.build(interface_options, &dirs)?; log::info!(action ="Built"; "application at: {}", tauri_utils::display_path(bin_path)); let app_settings = interface.app_settings(); - if !options.no_bundle && (config_.bundle.active || options.bundles.is_some()) { + if !options.no_bundle && (config.bundle.active || options.bundles.is_some()) { crate::bundle::bundle( &options.into(), verbosity, ci, &interface, - &app_settings, - config_, + &*app_settings, + &config, + &dirs, &out_dir, )?; } @@ -144,15 +140,14 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> { pub fn setup( interface: &AppInterface, options: &mut Options, - config: ConfigHandle, + config: &ConfigMetadata, + dirs: &Dirs, mobile: bool, ) -> Result<()> { - let tauri_path = tauri_dir(); - // TODO: Maybe optimize this to run in parallel in the future // see https://github.com/tauri-apps/tauri/pull/13993#discussion_r2280697117 log::info!("Looking up installed tauri packages to check mismatched versions..."); - if let Err(error) = check_mismatched_packages(frontend_dir(), tauri_path) { + if let Err(error) = check_mismatched_packages(dirs.frontend, dirs.tauri) { if options.ignore_version_mismatches { log::error!("{error}"); } else { @@ -160,46 +155,47 @@ pub fn setup( } } - set_current_dir(tauri_path).context("failed to set current directory")?; + set_current_dir(dirs.tauri).context("failed to set current directory")?; - let config_guard = config.lock().unwrap(); - let config_ = config_guard.as_ref().unwrap(); - - let bundle_identifier_source = config_ + let bundle_identifier_source = config .find_bundle_identifier_overwriter() .unwrap_or_else(|| "tauri.conf.json".into()); - if config_.identifier == "com.tauri.dev" { + if config.identifier == "com.tauri.dev" { crate::error::bail!( "You must change the bundle identifier in `{bundle_identifier_source} identifier`. The default value `com.tauri.dev` is not allowed as it must be unique across applications.", ); } - if config_ + if config .identifier .chars() .any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.')) { crate::error::bail!( - "The bundle identifier \"{}\" set in `{} identifier`. The bundle identifier string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).", - config_.identifier, - bundle_identifier_source + "The bundle identifier \"{}\" set in `{bundle_identifier_source:?} identifier`. The bundle identifier string must contain only alphanumeric characters (A-Z, a-z, and 0-9), hyphens (-), and periods (.).", + config.identifier, ); } - if config_.identifier.ends_with(".app") { + if config.identifier.ends_with(".app") { log::warn!( - "The bundle identifier \"{}\" set in `{} identifier` ends with `.app`. This is not recommended because it conflicts with the application bundle extension on macOS.", - config_.identifier, - bundle_identifier_source + "The bundle identifier \"{}\" set in `{bundle_identifier_source:?} identifier` ends with `.app`. This is not recommended because it conflicts with the application bundle extension on macOS.", + config.identifier, ); } - if let Some(before_build) = config_.build.before_build_command.clone() { - helpers::run_hook("beforeBuildCommand", before_build, interface, options.debug)?; + if let Some(before_build) = config.build.before_build_command.clone() { + helpers::run_hook( + "beforeBuildCommand", + before_build, + interface, + options.debug, + dirs.frontend, + )?; } - if let Some(FrontendDist::Directory(web_asset_path)) = &config_.build.frontend_dist { + if let Some(FrontendDist::Directory(web_asset_path)) = &config.build.frontend_dist { if !web_asset_path.exists() { let absolute_path = web_asset_path .parent() @@ -224,7 +220,7 @@ pub fn setup( // Issue #13287 - Allow the use of target dir inside frontendDist/distDir // https://github.com/tauri-apps/tauri/issues/13287 - let target_path = get_cargo_target_dir(&options.args)?; + let target_path = get_cargo_target_dir(&options.args, dirs.tauri)?; let mut out_folders = Vec::new(); if let Ok(web_asset_canonical) = dunce::canonicalize(web_asset_path) { if let Ok(relative_path) = target_path.strip_prefix(&web_asset_canonical) { @@ -252,13 +248,12 @@ pub fn setup( } if options.runner.is_none() { - options.runner = config_.build.runner.clone(); + options.runner = config.build.runner.clone(); } options .features - .get_or_insert(Vec::new()) - .extend(config_.build.features.clone().unwrap_or_default()); + .extend_from_slice(config.build.features.as_deref().unwrap_or_default()); interface.build_options(&mut options.args, &mut options.features, mobile); Ok(()) diff --git a/crates/tauri-cli/src/bundle.rs b/crates/tauri-cli/src/bundle.rs index e48aee197..638c215e9 100644 --- a/crates/tauri-cli/src/bundle.rs +++ b/crates/tauri-cli/src/bundle.rs @@ -16,8 +16,8 @@ use crate::{ error::{Context, ErrorExt}, helpers::{ self, - app_paths::tauri_dir, - config::{get as get_config, ConfigMetadata}, + app_paths::Dirs, + config::{get_config, ConfigMetadata}, updater_signature, }, interface::{AppInterface, AppSettings, Interface}, @@ -71,7 +71,7 @@ pub struct Options { pub config: Vec, /// Space or comma separated list of features, should be the same features passed to `tauri build` if any. #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// Target triple to build against. /// /// It must be one of the values outputted by `$rustc --print target-list` or `universal-apple-darwin` for an universal macOS application. @@ -118,7 +118,7 @@ impl From for Options { } pub fn command(options: Options, verbosity: u8) -> crate::Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); let ci = options.ci; @@ -131,35 +131,30 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> { let config = get_config( target, &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, )?; - let interface = AppInterface::new( - config.lock().unwrap().as_ref().unwrap(), - options.target.clone(), - )?; + let interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?; - let tauri_path = tauri_dir(); - std::env::set_current_dir(tauri_path).context("failed to set current directory")?; + std::env::set_current_dir(dirs.tauri).context("failed to set current directory")?; - let config_guard = config.lock().unwrap(); - let config_ = config_guard.as_ref().unwrap(); - - if let Some(minimum_system_version) = &config_.bundle.macos.minimum_system_version { + if let Some(minimum_system_version) = &config.bundle.macos.minimum_system_version { std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version); } let app_settings = interface.app_settings(); let interface_options = options.clone().into(); - let out_dir = app_settings.out_dir(&interface_options)?; + let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?; bundle( &options, verbosity, ci, &interface, - &app_settings, - config_, + &*app_settings, + &config, + &dirs, &out_dir, ) } @@ -170,8 +165,9 @@ pub fn bundle( verbosity: u8, ci: bool, interface: &AppInterface, - app_settings: &std::sync::Arc, + app_settings: &A, config: &ConfigMetadata, + dirs: &Dirs, out_dir: &Path, ) -> crate::Result<()> { let package_types: Vec = if let Some(bundles) = &options.bundles { @@ -198,12 +194,19 @@ pub fn bundle( before_bundle, interface, options.debug, + dirs.frontend, )?; } } let mut settings = app_settings - .get_bundler_settings(options.clone().into(), config, out_dir, package_types) + .get_bundler_settings( + options.clone().into(), + config, + out_dir, + package_types, + dirs.tauri, + ) .with_context(|| "failed to build bundler settings")?; settings.set_no_sign(options.no_sign); @@ -249,6 +252,11 @@ fn sign_updaters( return Ok(()); } + if settings.no_sign() { + log::warn!("Updater signing is skipped due to --no-sign flag."); + return Ok(()); + } + // get the public key let pubkey = &update_settings.pubkey; // check if pubkey points to a file... diff --git a/crates/tauri-cli/src/dev.rs b/crates/tauri-cli/src/dev.rs index 9179e9cfd..a66186919 100644 --- a/crates/tauri-cli/src/dev.rs +++ b/crates/tauri-cli/src/dev.rs @@ -5,11 +5,9 @@ use crate::{ error::{Context, ErrorExt}, helpers::{ - app_paths::{frontend_dir, tauri_dir}, + app_paths::Dirs, command_env, - config::{ - get as get_config, reload as reload_config, BeforeDevCommand, ConfigHandle, FrontendDist, - }, + config::{get_config, reload_config, BeforeDevCommand, ConfigMetadata, FrontendDist}, }, info::plugins::check_mismatched_packages, interface::{AppInterface, ExitReason, Interface}, @@ -34,7 +32,7 @@ use std::{ mod builtin_dev_server; static BEFORE_DEV: OnceLock>> = OnceLock::new(); -static KILL_BEFORE_DEV_FLAG: OnceLock = OnceLock::new(); +static KILL_BEFORE_DEV_FLAG: AtomicBool = AtomicBool::new(false); #[cfg(unix)] const KILL_CHILDREN_SCRIPT: &[u8] = include_bytes!("../scripts/kill-children.sh"); @@ -57,7 +55,7 @@ pub struct Options { pub target: Option, /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// Exit on panic #[clap(short, long)] pub exit_on_panic: bool, @@ -99,61 +97,57 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); - let r = command_internal(options); + let r = command_internal(options, dirs); if r.is_err() { kill_before_dev_process(); } r } -fn command_internal(mut options: Options) -> Result<()> { +fn command_internal(mut options: Options, dirs: Dirs) -> Result<()> { let target = options .target .as_deref() .map(Target::from_triple) .unwrap_or_else(Target::current); - let config = get_config( + let mut config = get_config( target, &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, )?; - let mut interface = AppInterface::new( - config.lock().unwrap().as_ref().unwrap(), - options.target.clone(), - )?; + let mut interface = AppInterface::new(&config, options.target.clone(), dirs.tauri)?; - setup(&interface, &mut options, config)?; + setup(&interface, &mut options, &mut config, &dirs)?; let exit_on_panic = options.exit_on_panic; let no_watch = options.no_watch; - interface.dev(options.into(), move |status, reason| { - on_app_exit(status, reason, exit_on_panic, no_watch) - }) + interface.dev( + &mut config, + options.into(), + move |status, reason| on_app_exit(status, reason, exit_on_panic, no_watch), + &dirs, + ) } -pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHandle) -> Result<()> { - let tauri_path = tauri_dir(); - +pub fn setup( + interface: &AppInterface, + options: &mut Options, + config: &mut ConfigMetadata, + dirs: &Dirs, +) -> Result<()> { std::thread::spawn(|| { - if let Err(error) = check_mismatched_packages(frontend_dir(), tauri_path) { + if let Err(error) = check_mismatched_packages(dirs.frontend, dirs.tauri) { log::error!("{error}"); } }); - set_current_dir(tauri_path).context("failed to set current directory")?; + set_current_dir(dirs.tauri).context("failed to set current directory")?; - if let Some(before_dev) = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .before_dev_command - .clone() - { + if let Some(before_dev) = config.build.before_dev_command.clone() { let (script, script_cwd, wait) = match before_dev { BeforeDevCommand::Script(s) if s.is_empty() => (None, None, false), BeforeDevCommand::Script(s) => (Some(s), None, false), @@ -161,7 +155,7 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand (Some(script), cwd.map(Into::into), wait) } }; - let cwd = script_cwd.unwrap_or_else(|| frontend_dir().clone()); + let cwd = script_cwd.unwrap_or_else(|| dirs.frontend.to_owned()); if let Some(before_dev) = script { log::info!(action = "Running"; "BeforeDevCommand (`{}`)", before_dev); let mut env = command_env(true); @@ -218,14 +212,13 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand let status = child_ .wait() .expect("failed to wait on \"beforeDevCommand\""); - if !(status.success() || KILL_BEFORE_DEV_FLAG.get().unwrap().load(Ordering::Relaxed)) { + if !(status.success() || KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed)) { log::error!("The \"beforeDevCommand\" terminated with a non-zero status code."); exit(status.code().unwrap_or(1)); } }); BEFORE_DEV.set(Mutex::new(child)).unwrap(); - KILL_BEFORE_DEV_FLAG.set(AtomicBool::default()).unwrap(); let _ = ctrlc::set_handler(move || { kill_before_dev_process(); @@ -236,45 +229,14 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand } if options.runner.is_none() { - options.runner = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .runner - .clone(); + options.runner = config.build.runner.clone(); } - let mut cargo_features = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .features - .clone() - .unwrap_or_default(); - if let Some(features) = &options.features { - cargo_features.extend(features.clone()); - } + let mut cargo_features = config.build.features.clone().unwrap_or_default(); + cargo_features.extend(options.features.clone()); - let mut dev_url = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .dev_url - .clone(); - let frontend_dist = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .frontend_dist - .clone(); + let mut dev_url = config.build.dev_url.clone(); + let frontend_dist = config.build.frontend_dist.clone(); if !options.no_dev_server && dev_url.is_none() { if let Some(FrontendDist::Directory(path)) = &frontend_dist { if path.exists() { @@ -297,19 +259,21 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand } }))); - reload_config(&options.config.iter().map(|c| &c.0).collect::>())?; + reload_config( + config, + &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, + )?; } } } if !options.no_dev_server_wait { if let Some(url) = dev_url { - let host = url - .host() - .unwrap_or_else(|| panic!("No host name in the URL")); + let host = url.host().expect("No host name in the URL"); let port = url .port_or_known_default() - .unwrap_or_else(|| panic!("No port number in the URL")); + .expect("No port number in the URL"); let addrs; let addr; let addrs = match host { @@ -352,16 +316,9 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand } if options.additional_watch_folders.is_empty() { - options.additional_watch_folders.extend( - config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .additional_watch_folders - .clone(), - ); + options + .additional_watch_folders + .extend(config.build.additional_watch_folders.clone()); } Ok(()) @@ -380,11 +337,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(); - let kill_before_dev_flag = KILL_BEFORE_DEV_FLAG.get().unwrap(); - if kill_before_dev_flag.load(Ordering::Relaxed) { + if KILL_BEFORE_DEV_FLAG.load(Ordering::Relaxed) { return; } - kill_before_dev_flag.store(true, Ordering::Relaxed); + KILL_BEFORE_DEV_FLAG.store(true, Ordering::Relaxed); #[cfg(windows)] { let powershell_path = std::env::var("SYSTEMROOT").map_or_else( diff --git a/crates/tauri-cli/src/dev/builtin_dev_server.rs b/crates/tauri-cli/src/dev/builtin_dev_server.rs index 067a64f67..1b49058ed 100644 --- a/crates/tauri-cli/src/dev/builtin_dev_server.rs +++ b/crates/tauri-cli/src/dev/builtin_dev_server.rs @@ -155,9 +155,9 @@ fn inject_address(html_bytes: Vec, address: &SocketAddr) -> Vec { } fn fs_read_scoped(path: PathBuf, scope: &Path) -> crate::Result> { - let path = dunce::canonicalize(&path).fs_context("failed to canonicalize path", path.clone())?; + let path = dunce::canonicalize(&path).fs_context("failed to canonicalize path", path)?; if path.starts_with(scope) { - std::fs::read(&path).fs_context("failed to read file", path.clone()) + std::fs::read(&path).fs_context("failed to read file", &path) } else { crate::error::bail!("forbidden path") } diff --git a/crates/tauri-cli/src/helpers/app_paths.rs b/crates/tauri-cli/src/helpers/app_paths.rs index 1bf1ef9b5..5b3e0d91a 100644 --- a/crates/tauri-cli/src/helpers/app_paths.rs +++ b/crates/tauri-cli/src/helpers/app_paths.rs @@ -23,6 +23,11 @@ const ENV_TAURI_APP_PATH: &str = "TAURI_APP_PATH"; // path to the frontend app directory, usually `/` const ENV_TAURI_FRONTEND_PATH: &str = "TAURI_FRONTEND_PATH"; +pub struct Dirs { + pub tauri: &'static Path, + pub frontend: &'static Path, +} + static FRONTEND_DIR: OnceLock = OnceLock::new(); static TAURI_DIR: OnceLock = OnceLock::new(); @@ -75,21 +80,13 @@ fn lookup bool>(dir: &Path, checker: F) -> Option { } fn env_tauri_app_path() -> Option { - std::env::var(ENV_TAURI_APP_PATH) - .map(PathBuf::from) - .ok()? - .canonicalize() - .ok() - .map(|p| dunce::simplified(&p).to_path_buf()) + let p = PathBuf::from(std::env::var_os(ENV_TAURI_APP_PATH)?); + dunce::canonicalize(p).ok() } fn env_tauri_frontend_path() -> Option { - std::env::var(ENV_TAURI_FRONTEND_PATH) - .map(PathBuf::from) - .ok()? - .canonicalize() - .ok() - .map(|p| dunce::simplified(&p).to_path_buf()) + let p = PathBuf::from(std::env::var_os(ENV_TAURI_FRONTEND_PATH)?); + dunce::canonicalize(p).ok() } pub fn resolve_tauri_dir() -> Option { @@ -130,8 +127,8 @@ pub fn resolve_tauri_dir() -> Option { }) } -pub fn resolve() { - TAURI_DIR.set(resolve_tauri_dir().unwrap_or_else(|| { +pub fn resolve_dirs() -> Dirs { + let tauri = TAURI_DIR.get_or_init(|| resolve_tauri_dir().unwrap_or_else(|| { let env_var_name = env_tauri_app_path().is_some().then(|| format!("`{ENV_TAURI_APP_PATH}`")); panic!("Couldn't recognize the {} folder as a Tauri project. It must contain a `{}`, `{}` or `{}` file in any subfolder.", env_var_name.as_deref().unwrap_or("current"), @@ -139,16 +136,11 @@ pub fn resolve() { ConfigFormat::Json5.into_file_name(), ConfigFormat::Toml.into_file_name() ) - })).expect("tauri dir already resolved"); - FRONTEND_DIR - .set(resolve_frontend_dir().unwrap_or_else(|| tauri_dir().parent().unwrap().to_path_buf())) - .expect("app dir already resolved"); -} - -pub fn tauri_dir() -> &'static PathBuf { - TAURI_DIR - .get() - .expect("app paths not initialized, this is a Tauri CLI bug") + })); + let frontend = FRONTEND_DIR.get_or_init(|| { + resolve_frontend_dir().unwrap_or_else(|| tauri.parent().unwrap().to_path_buf()) + }); + Dirs { tauri, frontend } } pub fn resolve_frontend_dir() -> Option { @@ -173,9 +165,3 @@ pub fn resolve_frontend_dir() -> Option { }) .map(|p| p.parent().unwrap().to_path_buf()) } - -pub fn frontend_dir() -> &'static PathBuf { - FRONTEND_DIR - .get() - .expect("app paths not initialized, this is a Tauri CLI bug") -} diff --git a/crates/tauri-cli/src/helpers/cargo_manifest.rs b/crates/tauri-cli/src/helpers/cargo_manifest.rs index 0ccf71790..b1bfa9a10 100644 --- a/crates/tauri-cli/src/helpers/cargo_manifest.rs +++ b/crates/tauri-cli/src/helpers/cargo_manifest.rs @@ -56,7 +56,7 @@ pub fn cargo_manifest_and_lock(tauri_dir: &Path) -> (Option, Opti .ok() .and_then(|manifest_contents| toml::from_str(&manifest_contents).ok()); - let lock: Option = get_workspace_dir() + let lock: Option = get_workspace_dir(tauri_dir) .ok() .and_then(|p| fs::read_to_string(p.join("Cargo.lock")).ok()) .and_then(|s| toml::from_str(&s).ok()); diff --git a/crates/tauri-cli/src/helpers/config.rs b/crates/tauri-cli/src/helpers/config.rs index f21ce4a4b..ce1f11c5b 100644 --- a/crates/tauri-cli/src/helpers/config.rs +++ b/crates/tauri-cli/src/helpers/config.rs @@ -12,9 +12,10 @@ pub use tauri_utils::{config::*, platform::Target}; use std::{ collections::HashMap, env::{current_dir, set_current_dir, set_var}, - ffi::OsStr, + ffi::{OsStr, OsString}, + path::Path, process::exit, - sync::{Arc, Mutex, OnceLock}, + sync::OnceLock, }; use crate::error::Context; @@ -30,7 +31,7 @@ pub struct ConfigMetadata { inner: Config, /// The config extensions (platform-specific config files or the config CLI argument). /// Maps the extension name to its value. - extensions: HashMap, + extensions: HashMap, } impl std::ops::Deref for ConfigMetadata { @@ -50,12 +51,11 @@ impl ConfigMetadata { } /// Checks which config is overwriting the bundle identifier. - pub fn find_bundle_identifier_overwriter(&self) -> Option { + pub fn find_bundle_identifier_overwriter(&self) -> Option { 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()); @@ -66,14 +66,11 @@ impl ConfigMetadata { } } -pub type ConfigHandle = Arc>>; - pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings { tauri_bundler::WixSettings { version: config.version, upgrade_code: config.upgrade_code, - fips_compliant: std::env::var("TAURI_BUNDLER_WIX_FIPS_COMPLIANT") - .ok() + fips_compliant: std::env::var_os("TAURI_BUNDLER_WIX_FIPS_COMPLIANT") .map(|v| v == "true") .unwrap_or(config.fips_compliant), language: tauri_bundler::WixLanguage(match config.language { @@ -141,32 +138,31 @@ pub fn custom_sign_settings( } } -fn config_handle() -> &'static ConfigHandle { - static CONFIG_HANDLE: OnceLock = OnceLock::new(); - CONFIG_HANDLE.get_or_init(Default::default) +fn config_schema_validator() -> &'static jsonschema::Validator { + // TODO: Switch to `LazyLock` when we bump MSRV to above 1.80 + static CONFIG_SCHEMA_VALIDATOR: OnceLock = OnceLock::new(); + CONFIG_SCHEMA_VALIDATOR.get_or_init(|| { + let schema: JsonValue = serde_json::from_str(include_str!("../../config.schema.json")) + .expect("Failed to parse config schema bundled in the tauri-cli"); + jsonschema::validator_for(&schema).expect("Config schema bundled in the tauri-cli is invalid") + }) } -/// Gets the static parsed config from `tauri.conf.json`. -fn get_internal( +fn load_config( merge_configs: &[&serde_json::Value], reload: bool, target: Target, -) -> crate::Result { - if !reload && config_handle().lock().unwrap().is_some() { - return Ok(config_handle().clone()); - } - - let tauri_dir = super::app_paths::tauri_dir(); + tauri_dir: &Path, +) -> crate::Result { let (mut config, config_path) = tauri_utils::config::parse::parse_value(target, tauri_dir.join("tauri.conf.json")) .context("failed to parse config")?; - let config_file_name = config_path.file_name().unwrap().to_string_lossy(); + let config_file_name = config_path.file_name().unwrap(); let mut extensions = HashMap::new(); 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)) = @@ -174,10 +170,7 @@ fn get_internal( .context("failed to parse platform config")? { merge(&mut config, &platform_config); - extensions.insert( - config_path.file_name().unwrap().to_str().unwrap().into(), - platform_config, - ); + extensions.insert(config_path.file_name().unwrap().into(), platform_config); } if !merge_configs.is_empty() { @@ -195,17 +188,14 @@ fn get_internal( if config_path.extension() == Some(OsStr::new("json")) || config_path.extension() == Some(OsStr::new("json5")) { - let schema: JsonValue = serde_json::from_str(include_str!("../../config.schema.json")) - .context("failed to parse config schema")?; - let validator = jsonschema::validator_for(&schema).expect("Invalid schema"); - let mut errors = validator.iter_errors(&config).peekable(); + let mut errors = config_schema_validator().iter_errors(&config).peekable(); if errors.peek().is_some() { for error in errors { let path = error.instance_path.into_iter().join(" > "); if path.is_empty() { - log::error!("`{}` error: {}", config_file_name, error); + log::error!("`{config_file_name:?}` error: {error}"); } else { - log::error!("`{}` error on `{}`: {}", config_file_name, path, error); + log::error!("`{config_file_name:?}` error on `{path}`: {error}"); } } if !reload { @@ -236,59 +226,54 @@ fn get_internal( std::env::set_var(REMOVE_UNUSED_COMMANDS_ENV_VAR, tauri_dir); } - *config_handle().lock().unwrap() = Some(ConfigMetadata { + Ok(ConfigMetadata { target, original_identifier, inner: config, extensions, - }); - - Ok(config_handle().clone()) + }) } -pub fn get(target: Target, merge_configs: &[&serde_json::Value]) -> crate::Result { - get_internal(merge_configs, false, target) +pub fn get_config( + target: Target, + merge_configs: &[&serde_json::Value], + tauri_dir: &Path, +) -> crate::Result { + load_config(merge_configs, false, target, tauri_dir) } -pub fn reload(merge_configs: &[&serde_json::Value]) -> crate::Result { - let target = config_handle() - .lock() - .unwrap() - .as_ref() - .map(|conf| conf.target); - if let Some(target) = target { - get_internal(merge_configs, true, target) - } else { - crate::error::bail!("config not loaded"); - } +pub fn reload_config( + config: &mut ConfigMetadata, + merge_configs: &[&serde_json::Value], + tauri_dir: &Path, +) -> crate::Result<()> { + let target = config.target; + *config = load_config(merge_configs, true, target, tauri_dir)?; + Ok(()) } /// merges the loaded config with the given value -pub fn merge_with(merge_configs: &[&serde_json::Value]) -> crate::Result { - let handle = config_handle(); - +pub fn merge_config_with( + config: &mut ConfigMetadata, + merge_configs: &[&serde_json::Value], +) -> crate::Result<()> { if merge_configs.is_empty() { - return Ok(handle.clone()); + return Ok(()); } - if let Some(config_metadata) = &mut *handle.lock().unwrap() { - let mut merge_config = serde_json::Value::Object(Default::default()); - for conf in merge_configs { - merge_patches(&mut merge_config, conf); - } - - let merge_config_str = serde_json::to_string(&merge_config).unwrap(); - set_var("TAURI_CONFIG", merge_config_str); - - let mut value = - serde_json::to_value(config_metadata.inner.clone()).context("failed to serialize config")?; - merge(&mut value, &merge_config); - config_metadata.inner = serde_json::from_value(value).context("failed to parse config")?; - - Ok(handle.clone()) - } else { - crate::error::bail!("config not loaded"); + let mut merge_config = serde_json::Value::Object(Default::default()); + for conf in merge_configs { + merge_patches(&mut merge_config, conf); } + + let merge_config_str = serde_json::to_string(&merge_config).unwrap(); + set_var("TAURI_CONFIG", merge_config_str); + + let mut value = + serde_json::to_value(config.inner.clone()).context("failed to serialize config")?; + merge(&mut value, &merge_config); + config.inner = serde_json::from_value(value).context("failed to parse config")?; + Ok(()) } /// Same as [`json_patch::merge`] but doesn't delete the key when the patch's value is `null` diff --git a/crates/tauri-cli/src/helpers/http.rs b/crates/tauri-cli/src/helpers/http.rs index 9dfee185a..14e07af9d 100644 --- a/crates/tauri-cli/src/helpers/http.rs +++ b/crates/tauri-cli/src/helpers/http.rs @@ -2,23 +2,25 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use ureq::{http::Response, Body}; +use ureq::{http::Response, Agent, Body}; + +const CLI_USER_AGENT: &str = concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),); pub fn get(url: &str) -> Result, ureq::Error> { + #[allow(unused_mut)] + let mut config_builder = ureq::Agent::config_builder() + .user_agent(CLI_USER_AGENT) + .proxy(ureq::Proxy::try_from_env()); + #[cfg(feature = "platform-certs")] { - let agent = ureq::Agent::config_builder() - .tls_config( - ureq::tls::TlsConfig::builder() - .root_certs(ureq::tls::RootCerts::PlatformVerifier) - .build(), - ) - .build() - .new_agent(); - agent.get(url).call() - } - #[cfg(not(feature = "platform-certs"))] - { - ureq::get(url).call() + config_builder = config_builder.tls_config( + ureq::tls::TlsConfig::builder() + .root_certs(ureq::tls::RootCerts::PlatformVerifier) + .build(), + ); } + + let agent: Agent = config_builder.build().into(); + agent.get(url).call() } diff --git a/crates/tauri-cli/src/helpers/mod.rs b/crates/tauri-cli/src/helpers/mod.rs index 06ff052ce..3d2a5f0e9 100644 --- a/crates/tauri-cli/src/helpers/mod.rs +++ b/crates/tauri-cli/src/helpers/mod.rs @@ -35,8 +35,6 @@ use crate::{ CommandExt, }; -use self::app_paths::frontend_dir; - pub fn command_env(debug: bool) -> HashMap<&'static str, String> { let mut map = HashMap::new(); @@ -78,13 +76,14 @@ pub fn run_hook( hook: HookCommand, interface: &AppInterface, debug: bool, + frontend_dir: &Path, ) -> crate::Result<()> { let (script, script_cwd) = match hook { HookCommand::Script(s) if s.is_empty() => (None, None), HookCommand::Script(s) => (Some(s), None), HookCommand::ScriptWithOptions { script, cwd } => (Some(script), cwd.map(Into::into)), }; - let cwd = script_cwd.unwrap_or_else(|| frontend_dir().clone()); + let cwd = script_cwd.unwrap_or_else(|| frontend_dir.to_owned()); if let Some(script) = script { log::info!(action = "Running"; "{} `{}`", name, script); diff --git a/crates/tauri-cli/src/helpers/npm.rs b/crates/tauri-cli/src/helpers/npm.rs index a39c5ffd0..eced925ac 100644 --- a/crates/tauri-cli/src/helpers/npm.rs +++ b/crates/tauri-cli/src/helpers/npm.rs @@ -332,13 +332,20 @@ impl PackageManager { version: String, } - let json: ListOutput = serde_json::from_str(&stdout).context("failed to parse npm list")?; + let json = if matches!(self, PackageManager::Pnpm) { + serde_json::from_str::>(&stdout) + .ok() + .and_then(|out| out.into_iter().next()) + .context("failed to parse pnpm list")? + } else { + serde_json::from_str::(&stdout).context("failed to parse npm list")? + }; for (package, dependency) in json.dependencies.into_iter().chain(json.dev_dependencies) { let version = dependency.version; if let Ok(version) = semver::Version::parse(&version) { versions.insert(package, version); } else { - log::error!("Failed to parse version `{version}` for NPM package `{package}`"); + log::debug!("Failed to parse version `{version}` for NPM package `{package}`"); } } Ok(versions) @@ -390,7 +397,7 @@ fn yarn_package_versions( if let Ok(version) = semver::Version::parse(version) { versions.insert(name.to_owned(), version); } else { - log::error!("Failed to parse version `{version}` for NPM package `{name}`"); + log::debug!("Failed to parse version `{version}` for NPM package `{name}`"); } } return Ok(versions); @@ -443,7 +450,7 @@ fn yarn_berry_package_versions( if let Ok(version) = semver::Version::parse(&version) { versions.insert(name.to_owned(), version); } else { - log::error!("Failed to parse version `{version}` for NPM package `{name}`"); + log::debug!("Failed to parse version `{version}` for NPM package `{name}`"); } } } diff --git a/crates/tauri-cli/src/helpers/updater_signature.rs b/crates/tauri-cli/src/helpers/updater_signature.rs index b7f03cafc..ba9012359 100644 --- a/crates/tauri-cli/src/helpers/updater_signature.rs +++ b/crates/tauri-cli/src/helpers/updater_signature.rs @@ -120,9 +120,14 @@ where { let bin_path = bin_path.as_ref(); // We need to append .sig at the end it's where the signature will be stored - let mut extension = bin_path.extension().unwrap().to_os_string(); - extension.push(".sig"); - let signature_path = bin_path.with_extension(extension); + // TODO: use with_added_extension when we bump MSRV to > 1.91' + let signature_path = if let Some(ext) = bin_path.extension() { + let mut extension = ext.to_os_string(); + extension.push(".sig"); + bin_path.with_extension(extension) + } else { + bin_path.with_extension("sig") + }; let trusted_comment = format!( "timestamp:{}\tfile:{}", @@ -146,10 +151,8 @@ where std::fs::write(&signature_path, encoded_signature.as_bytes()) .fs_context("failed to write signature file", signature_path.clone())?; Ok(( - fs::canonicalize(&signature_path).fs_context( - "failed to canonicalize signature file", - signature_path.clone(), - )?, + fs::canonicalize(&signature_path) + .fs_context("failed to canonicalize signature file", &signature_path)?, signature_box, )) } @@ -203,7 +206,7 @@ where mod tests { const PRIVATE_KEY: &str = "dW50cnVzdGVkIGNvbW1lbnQ6IHJzaWduIGVuY3J5cHRlZCBzZWNyZXQga2V5ClJXUlRZMEl5dkpDN09RZm5GeVAzc2RuYlNzWVVJelJRQnNIV2JUcGVXZUplWXZXYXpqUUFBQkFBQUFBQUFBQUFBQUlBQUFBQTZrN2RnWGh5dURxSzZiL1ZQSDdNcktiaHRxczQwMXdQelRHbjRNcGVlY1BLMTBxR2dpa3I3dDE1UTVDRDE4MXR4WlQwa1BQaXdxKy9UU2J2QmVSNXhOQWFDeG1GSVllbUNpTGJQRkhhTnROR3I5RmdUZi90OGtvaGhJS1ZTcjdZU0NyYzhQWlQ5cGM9Cg=="; - // we use minisign=0.7.3 to prevent a breaking change + // minisign >=0.7.4,<0.8.0 couldn't handle empty passwords. #[test] fn empty_password_is_valid() { let path = std::env::temp_dir().join("minisign-password-text.txt"); diff --git a/crates/tauri-cli/src/icon.rs b/crates/tauri-cli/src/icon.rs index e072d2c5a..4945fb826 100644 --- a/crates/tauri-cli/src/icon.rs +++ b/crates/tauri-cli/src/icon.rs @@ -4,11 +4,11 @@ use crate::{ error::{Context, Error, ErrorExt}, - helpers::app_paths::tauri_dir, Result, }; use std::{ + borrow::Cow, collections::HashMap, fs::{create_dir_all, File}, io::{BufWriter, Write}, @@ -25,8 +25,9 @@ use image::{ png::{CompressionType, FilterType as PngFilterType, PngEncoder}, }, imageops::FilterType, - open, DynamicImage, ExtendedColorType, GenericImageView, ImageBuffer, ImageEncoder, Rgba, + open, DynamicImage, ExtendedColorType, GenericImageView, ImageBuffer, ImageEncoder, Pixel, Rgba, }; +use rayon::iter::ParallelIterator; use resvg::{tiny_skia, usvg}; use serde::Deserialize; @@ -123,7 +124,7 @@ impl Source { } } - fn resize_exact(&self, size: u32) -> Result { + fn resize_exact(&self, size: u32) -> DynamicImage { match self { Self::Svg(svg) => { let mut pixmap = tiny_skia::Pixmap::new(size, size).unwrap(); @@ -133,14 +134,49 @@ impl Source { tiny_skia::Transform::from_scale(scale, scale), &mut pixmap.as_mut(), ); - let img_buffer = ImageBuffer::from_raw(size, size, pixmap.take()).unwrap(); - Ok(DynamicImage::ImageRgba8(img_buffer)) + // Switch to use `Pixmap::take_demultiplied` in the future when it's published + // https://github.com/linebender/tiny-skia/blob/624257c0feb394bf6c4d0d688f8ea8030aae320f/src/pixmap.rs#L266 + let img_buffer = ImageBuffer::from_par_fn(size, size, |x, y| { + let pixel = pixmap.pixel(x, y).unwrap().demultiply(); + Rgba([pixel.red(), pixel.green(), pixel.blue(), pixel.alpha()]) + }); + DynamicImage::ImageRgba8(img_buffer) + } + Self::DynamicImage(image) => { + // image.resize_exact(size, size, FilterType::Lanczos3) + resize_image(image, size, size) } - Self::DynamicImage(i) => Ok(i.resize_exact(size, size, FilterType::Lanczos3)), } } } +// `image` does not use premultiplied alpha in resize, so we do it manually here, +// see https://github.com/image-rs/image/issues/1655 +fn resize_image(image: &DynamicImage, new_width: u32, new_height: u32) -> DynamicImage { + // Premultiply alpha + let premultiplied_image = ImageBuffer::from_par_fn(image.width(), image.height(), |x, y| { + let mut pixel = image.get_pixel(x, y); + let alpha = pixel.0[3] as f32 / u8::MAX as f32; + pixel.apply_without_alpha(|channel_value| (channel_value as f32 * alpha) as u8); + pixel + }); + + let mut resized = image::imageops::resize( + &premultiplied_image, + new_width, + new_height, + FilterType::Lanczos3, + ); + + // Demultiply alpha + resized.par_pixels_mut().for_each(|pixel| { + let alpha = pixel.0[3] as f32 / u8::MAX as f32; + pixel.apply_without_alpha(|channel_value| (channel_value as f32 / alpha) as u8); + }); + + DynamicImage::ImageRgba8(resized) +} + fn read_source(path: PathBuf) -> Result { if let Some(extension) = path.extension() { if extension == "svg" { @@ -157,7 +193,7 @@ fn read_source(path: PathBuf) -> Result { ..Default::default() }; - let svg_data = std::fs::read(&path).unwrap(); + let svg_data = std::fs::read(&path).fs_context("Failed to read source icon", &path)?; usvg::Tree::from_data(&svg_data, &opt).unwrap() }; @@ -200,8 +236,8 @@ fn parse_bg_color(bg_color_string: &String) -> Result> { pub fn command(options: Options) -> Result<()> { let input = options.input; let out_dir = options.output.unwrap_or_else(|| { - crate::helpers::app_paths::resolve(); - tauri_dir().join("icons") + let dirs = crate::helpers::app_paths::resolve_dirs(); + dirs.tauri.join("icons") }); let png_icon_sizes = options.png.unwrap_or_default(); @@ -243,19 +279,15 @@ pub fn command(options: Options) -> Result<()> { android(&source, &input, manifest, &bg_color_string, &out_dir) .context("Failed to generate android icons")?; } else { - for target in png_icon_sizes - .into_iter() - .map(|size| { - let name = format!("{size}x{size}.png"); - let out_path = out_dir.join(&name); - PngEntry { - name, - out_path, - size, - } - }) - .collect::>() - { + for target in png_icon_sizes.into_iter().map(|size| { + let name = format!("{size}x{size}.png"); + let out_path = out_dir.join(&name); + PngEntry { + name, + out_path, + size, + } + }) { log::info!(action = "PNG"; "Creating {}", target.name); resize_and_save_png(&source, target.size, &target.out_path, None, None)?; } @@ -303,7 +335,7 @@ fn icns(source: &Source, out_dir: &Path) -> Result<()> { let size = entry.size; let mut buf = Vec::new(); - let image = source.resize_exact(size)?; + let image = source.resize_exact(size); write_png(image.as_bytes(), &mut buf, size).context("failed to write output file")?; @@ -338,7 +370,7 @@ fn ico(source: &Source, out_dir: &Path) -> Result<()> { let mut frames = Vec::new(); for size in [32, 16, 24, 48, 64, 256] { - let image = source.resize_exact(size)?; + let image = source.resize_exact(size); // Only the 256px layer can be compressed according to the ico specs. if size == 256 { @@ -769,7 +801,7 @@ fn resize_png( bg: Option, scale_percent: Option, ) -> Result { - let mut image = source.resize_exact(size)?; + let mut image = source.resize_exact(size); match bg { Some(Background::Color(bg_color)) => { @@ -783,7 +815,7 @@ fn resize_png( image = bg_img.into(); } Some(Background::Image(bg_source)) => { - let mut bg = bg_source.resize_exact(size)?; + let mut bg = bg_source.resize_exact(size); let fg = scale_percent .map(|scale| resize_asset(&image, size, scale)) @@ -863,9 +895,10 @@ fn content_bounds(img: &DynamicImage) -> Option<(u32, u32, u32, u32)> { fn resize_asset(img: &DynamicImage, target_size: u32, scale_percent: f32) -> DynamicImage { let cropped = if let Some((x, y, cw, ch)) = content_bounds(img) { - img.crop_imm(x, y, cw, ch) + // TODO: Use `&` here instead when we raise MSRV to above 1.79 + Cow::Owned(img.crop_imm(x, y, cw, ch)) } else { - img.clone() + Cow::Borrowed(img) }; let (cw, ch) = cropped.dimensions(); @@ -875,7 +908,7 @@ fn resize_asset(img: &DynamicImage, target_size: u32, scale_percent: f32) -> Dyn let new_w = (cw as f32 * scale).round() as u32; let new_h = (ch as f32 * scale).round() as u32; - let resized = image::imageops::resize(&cropped, new_w, new_h, image::imageops::Lanczos3); + let resized = resize_image(&cropped, new_w, new_h); // Place on transparent square canvas let mut canvas = ImageBuffer::from_pixel(target_size, target_size, Rgba([0, 0, 0, 0])); diff --git a/crates/tauri-cli/src/info/app.rs b/crates/tauri-cli/src/info/app.rs index 624d79bd3..6814c96bd 100644 --- a/crates/tauri-cli/src/info/app.rs +++ b/crates/tauri-cli/src/info/app.rs @@ -3,56 +3,46 @@ // SPDX-License-Identifier: MIT use super::SectionItem; +use crate::helpers::config::ConfigMetadata; use crate::helpers::framework; -use std::{ - fs::read_to_string, - path::{Path, PathBuf}, -}; -use tauri_utils::platform::Target; +use std::{fs::read_to_string, path::PathBuf}; -pub fn items(frontend_dir: Option<&PathBuf>, tauri_dir: Option<&Path>) -> Vec { +pub fn items(config: &ConfigMetadata, frontend_dir: Option<&PathBuf>) -> Vec { let mut items = Vec::new(); - if tauri_dir.is_some() { - if let Ok(config) = crate::helpers::config::get(Target::current(), &[]) { - let config_guard = config.lock().unwrap(); - let config = config_guard.as_ref().unwrap(); + let bundle_or_build = if config.bundle.active { + "bundle" + } else { + "build" + }; + items.push(SectionItem::new().description(format!("build-type: {bundle_or_build}"))); - let bundle_or_build = if config.bundle.active { - "bundle" - } else { - "build" - }; - items.push(SectionItem::new().description(format!("build-type: {bundle_or_build}"))); + let csp = config + .app + .security + .csp + .clone() + .map(|c| c.to_string()) + .unwrap_or_else(|| "unset".to_string()); + items.push(SectionItem::new().description(format!("CSP: {csp}"))); - let csp = config - .app - .security - .csp - .clone() - .map(|c| c.to_string()) - .unwrap_or_else(|| "unset".to_string()); - items.push(SectionItem::new().description(format!("CSP: {csp}"))); + if let Some(frontend_dist) = &config.build.frontend_dist { + items.push(SectionItem::new().description(format!("frontendDist: {frontend_dist}"))); + } - if let Some(frontend_dist) = &config.build.frontend_dist { - items.push(SectionItem::new().description(format!("frontendDist: {frontend_dist}"))); + if let Some(dev_url) = &config.build.dev_url { + items.push(SectionItem::new().description(format!("devUrl: {dev_url}"))); + } + + if let Some(frontend_dir) = frontend_dir { + if let Ok(package_json) = read_to_string(frontend_dir.join("package.json")) { + let (framework, bundler) = framework::infer_from_package_json(&package_json); + + if let Some(framework) = framework { + items.push(SectionItem::new().description(format!("framework: {framework}"))); } - if let Some(dev_url) = &config.build.dev_url { - items.push(SectionItem::new().description(format!("devUrl: {dev_url}"))); - } - - if let Some(frontend_dir) = frontend_dir { - if let Ok(package_json) = read_to_string(frontend_dir.join("package.json")) { - let (framework, bundler) = framework::infer_from_package_json(&package_json); - - if let Some(framework) = framework { - items.push(SectionItem::new().description(format!("framework: {framework}"))); - } - - if let Some(bundler) = bundler { - items.push(SectionItem::new().description(format!("bundler: {bundler}"))); - } - } + if let Some(bundler) = bundler { + items.push(SectionItem::new().description(format!("bundler: {bundler}"))); } } } diff --git a/crates/tauri-cli/src/info/mod.rs b/crates/tauri-cli/src/info/mod.rs index 0f89d31c1..cb52415a9 100644 --- a/crates/tauri-cli/src/info/mod.rs +++ b/crates/tauri-cli/src/info/mod.rs @@ -12,6 +12,7 @@ use colored::{ColoredString, Colorize}; use dialoguer::{theme::ColorfulTheme, Confirm}; use serde::Deserialize; use std::fmt::{self, Display, Formatter}; +use tauri_utils::platform::Target; mod app; mod env_nodejs; @@ -265,11 +266,6 @@ pub fn command(options: Options) -> Result<()> { let frontend_dir = resolve_frontend_dir(); let tauri_dir = resolve_tauri_dir(); - if tauri_dir.is_some() { - // safe to initialize - crate::helpers::app_paths::resolve(); - } - let package_manager = frontend_dir .as_ref() .map(packages_nodejs::package_manager) @@ -313,9 +309,11 @@ pub fn command(options: Options) -> Result<()> { interactive, items: Vec::new(), }; - app - .items - .extend(app::items(frontend_dir.as_ref(), tauri_dir.as_deref())); + if let Some(tauri_dir) = &tauri_dir { + if let Ok(config) = crate::helpers::config::get_config(Target::current(), &[], tauri_dir) { + app.items.extend(app::items(&config, frontend_dir.as_ref())); + }; + } environment.display(); diff --git a/crates/tauri-cli/src/info/plugins.rs b/crates/tauri-cli/src/info/plugins.rs index 989abe356..d0ede6b25 100644 --- a/crates/tauri-cli/src/info/plugins.rs +++ b/crates/tauri-cli/src/info/plugins.rs @@ -72,7 +72,10 @@ pub fn installed_tauri_packages( crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), crate_name).version?; let crate_version = semver::Version::parse(&crate_version) .inspect_err(|_| { - log::error!("Failed to parse version `{crate_version}` for crate `{crate_name}`"); + // On first run there's no lockfile yet so we get the version requirement from Cargo.toml. + // In our templates that's `2` which is not a valid semver version but a version requirement. + // log::error confused users so we use log::debug to still be able to see this error if needed. + log::debug!("Failed to parse version `{crate_version}` for crate `{crate_name}`"); }) .ok()?; Some((crate_name.clone(), crate_version)) @@ -108,33 +111,27 @@ pub fn items( ) -> Vec { let mut items = Vec::new(); - if tauri_dir.is_some() || frontend_dir.is_some() { - if let Some(tauri_dir) = tauri_dir { - let (manifest, lock) = cargo_manifest_and_lock(tauri_dir); + if let Some(tauri_dir) = tauri_dir { + let (manifest, lock) = cargo_manifest_and_lock(tauri_dir); - for p in helpers::plugins::known_plugins().keys() { - let dep = format!("tauri-plugin-{p}"); - let crate_version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), &dep); - if !crate_version.has_version() { - continue; - } - let item = packages_rust::rust_section_item(&dep, crate_version); - items.push(item); - - let Some(frontend_dir) = frontend_dir else { - continue; - }; - - let package = format!("@tauri-apps/plugin-{p}"); - - let item = packages_nodejs::nodejs_section_item( - package, - None, - frontend_dir.clone(), - package_manager, - ); - items.push(item); + for p in helpers::plugins::known_plugins().keys() { + let dep = format!("tauri-plugin-{p}"); + let crate_version = crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), &dep); + if !crate_version.has_version() { + continue; } + let item = packages_rust::rust_section_item(&dep, crate_version); + items.push(item); + + let Some(frontend_dir) = frontend_dir else { + continue; + }; + + let package = format!("@tauri-apps/plugin-{p}"); + + let item = + packages_nodejs::nodejs_section_item(package, None, frontend_dir.clone(), package_manager); + items.push(item); } } diff --git a/crates/tauri-cli/src/init.rs b/crates/tauri-cli/src/init.rs index a72137388..a809ba317 100644 --- a/crates/tauri-cli/src/init.rs +++ b/crates/tauri-cli/src/init.rs @@ -78,8 +78,8 @@ impl Options { let package_json_path = PathBuf::from(&self.directory).join("package.json"); let init_defaults = if package_json_path.exists() { - let package_json_text = read_to_string(&package_json_path) - .fs_context("failed to read", package_json_path.clone())?; + let package_json_text = + read_to_string(&package_json_path).fs_context("failed to read", &package_json_path)?; let package_json: crate::PackageJson = serde_json::from_str(&package_json_text).context("failed to parse JSON")?; let (framework, _) = infer_framework(&package_json_text); diff --git a/crates/tauri-cli/src/inspect.rs b/crates/tauri-cli/src/inspect.rs index 68d040ed2..de26dd984 100644 --- a/crates/tauri-cli/src/inspect.rs +++ b/crates/tauri-cli/src/inspect.rs @@ -1,6 +1,7 @@ // Copyright 2019-2024 Tauri Programme within The Commons Conservancy // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +use std::path::Path; use crate::Result; use clap::{Parser, Subcommand}; @@ -8,7 +9,7 @@ use clap::{Parser, Subcommand}; use crate::interface::{AppInterface, AppSettings, Interface}; #[derive(Debug, Parser)] -#[clap(about = "Manage or create permissions for your app or plugin")] +#[clap(about = "Inspect values used by Tauri")] pub struct Cli { #[clap(subcommand)] command: Commands, @@ -21,36 +22,34 @@ enum Commands { } pub fn command(cli: Cli) -> Result<()> { + let dirs = crate::helpers::app_paths::resolve_dirs(); match cli.command { - Commands::WixUpgradeCode => wix_upgrade_code(), + Commands::WixUpgradeCode => wix_upgrade_code(dirs.tauri), } } // NOTE: if this is ever changed, make sure to also update Wix upgrade code generation in tauri-bundler -fn wix_upgrade_code() -> Result<()> { - crate::helpers::app_paths::resolve(); - +fn wix_upgrade_code(tauri_dir: &Path) -> Result<()> { let target = tauri_utils::platform::Target::Windows; - let config = crate::helpers::config::get(target, &[])?; + let config = crate::helpers::config::get_config(target, &[], tauri_dir)?; - let interface = AppInterface::new(config.lock().unwrap().as_ref().unwrap(), None)?; + let interface = AppInterface::new(&config, None, tauri_dir)?; let product_name = interface.app_settings().get_package_settings().product_name; let upgrade_code = uuid::Uuid::new_v5( &uuid::Uuid::NAMESPACE_DNS, format!("{product_name}.exe.app.x64").as_bytes(), - ) - .to_string(); + ); log::info!("Default WiX Upgrade Code, derived from {product_name}: {upgrade_code}"); - if let Some(code) = config.lock().unwrap().as_ref().and_then(|c| { - c.bundle - .windows - .wix - .as_ref() - .and_then(|wix| wix.upgrade_code) - }) { + if let Some(code) = config + .bundle + .windows + .wix + .as_ref() + .and_then(|wix| wix.upgrade_code) + { log::info!("Application Upgrade Code override: {code}"); } diff --git a/crates/tauri-cli/src/interface/mod.rs b/crates/tauri-cli/src/interface/mod.rs index e0f74ebf7..dc15e7ecb 100644 --- a/crates/tauri-cli/src/interface/mod.rs +++ b/crates/tauri-cli/src/interface/mod.rs @@ -11,7 +11,10 @@ use std::{ sync::Arc, }; -use crate::{error::Context, helpers::config::Config}; +use crate::{ + error::Context, helpers::app_paths::Dirs, helpers::config::Config, + helpers::config::ConfigMetadata, +}; use tauri_bundler::bundle::{PackageType, Settings, SettingsBuilder}; pub use rust::{MobileOptions, Options, Rust as AppInterface, WatcherOptions}; @@ -32,9 +35,14 @@ pub trait AppSettings { options: &Options, config: &Config, features: &[String], + tauri_dir: &Path, ) -> crate::Result; - fn app_binary_path(&self, options: &Options) -> crate::Result; - fn get_binaries(&self) -> crate::Result>; + fn app_binary_path(&self, options: &Options, tauri_dir: &Path) -> crate::Result; + fn get_binaries( + &self, + options: &Options, + tauri_dir: &Path, + ) -> crate::Result>; fn app_name(&self) -> Option; fn lib_name(&self) -> Option; @@ -44,9 +52,10 @@ pub trait AppSettings { config: &Config, out_dir: &Path, package_types: Vec, + tauri_dir: &Path, ) -> crate::Result { let no_default_features = options.args.contains(&"--no-default-features".into()); - let mut enabled_features = options.features.clone().unwrap_or_default(); + let mut enabled_features = options.features.clone(); if !no_default_features { enabled_features.push("default".into()); } @@ -57,7 +66,7 @@ pub trait AppSettings { tauri_utils::platform::target_triple().context("failed to get target triple")? }; - let mut bins = self.get_binaries()?; + let mut bins = self.get_binaries(&options, tauri_dir)?; if let Some(main_binary_name) = &config.main_binary_name { let main = bins.iter_mut().find(|b| b.main()).context("no main bin?")?; main.set_name(main_binary_name.to_owned()); @@ -65,7 +74,7 @@ pub trait AppSettings { let mut settings_builder = SettingsBuilder::new() .package_settings(self.get_package_settings()) - .bundle_settings(self.get_bundle_settings(&options, config, &enabled_features)?) + .bundle_settings(self.get_bundle_settings(&options, config, &enabled_features, tauri_dir)?) .binaries(bins) .project_out_directory(out_dir) .target(target) @@ -73,7 +82,7 @@ pub trait AppSettings { if config.bundle.use_local_tools_dir { settings_builder = settings_builder.local_tools_directory( - rust::get_cargo_metadata() + rust::get_cargo_metadata(tauri_dir) .context("failed to get cargo metadata")? .target_directory, ) @@ -99,23 +108,31 @@ pub enum ExitReason { pub trait Interface: Sized { type AppSettings: AppSettings; - fn new(config: &Config, target: Option) -> crate::Result; + 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) -> crate::Result; + fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result; fn dev, ExitReason) + Send + Sync + 'static>( &mut self, + config: &mut ConfigMetadata, options: Options, on_exit: F, + dirs: &Dirs, ) -> crate::Result<()>; - fn mobile_dev crate::Result>>( + fn mobile_dev< + R: Fn(MobileOptions, &ConfigMetadata) -> crate::Result>, + >( &mut self, + config: &mut ConfigMetadata, options: MobileOptions, runner: R, + dirs: &Dirs, ) -> crate::Result<()>; - fn watch crate::Result>>( + fn watch crate::Result>>( &mut self, + config: &mut ConfigMetadata, 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 3338c6dae..40e484d8c 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; @@ -31,8 +31,8 @@ use super::{AppSettings, DevProcess, ExitReason, Interface}; use crate::{ error::{Context, Error, ErrorExt}, helpers::{ - app_paths::{frontend_dir, tauri_dir}, - config::{nsis_settings, reload as reload_config, wix_settings, BundleResources, Config}, + app_paths::Dirs, + config::{nsis_settings, reload_config, wix_settings, BundleResources, Config, ConfigMetadata}, }, ConfigValue, }; @@ -51,7 +51,7 @@ pub struct Options { pub runner: Option, pub debug: bool, pub target: Option, - pub features: Option>, + pub features: Vec, pub args: Vec, pub config: Vec, pub no_watch: bool, @@ -108,7 +108,7 @@ impl From for Options { #[derive(Debug, Clone)] pub struct MobileOptions { pub debug: bool, - pub features: Option>, + pub features: Vec, pub args: Vec, pub config: Vec, pub no_watch: bool, @@ -137,7 +137,7 @@ pub struct Rust { impl Interface for Rust { type AppSettings = RustAppSettings; - fn new(config: &Config, target: Option) -> crate::Result { + 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| { @@ -147,14 +147,9 @@ impl Interface for Rust { }) .unwrap(); watcher - .watch(tauri_dir().join("Cargo.toml"), RecursiveMode::NonRecursive) - .with_context(|| { - format!( - "failed to watch {}", - tauri_dir().join("Cargo.toml").display() - ) - })?; - let (manifest, modified) = rewrite_manifest(config)?; + .watch(tauri_dir.join("Cargo.toml"), RecursiveMode::NonRecursive) + .with_context(|| format!("failed to watch {}", tauri_dir.join("Cargo.toml").display()))?; + let (manifest, modified) = rewrite_manifest(config, tauri_dir)?; if modified { // Wait for the modified event so we don't trigger a re-build later on let _ = rx.recv_timeout(Duration::from_secs(2)); @@ -172,7 +167,7 @@ impl Interface for Rust { ); } - let app_settings = RustAppSettings::new(config, manifest, target)?; + let app_settings = RustAppSettings::new(config, manifest, target, tauri_dir)?; Ok(Self { app_settings: Arc::new(app_settings), @@ -186,20 +181,23 @@ impl Interface for Rust { self.app_settings.clone() } - fn build(&mut self, options: Options) -> crate::Result { + fn build(&mut self, options: Options, dirs: &Dirs) -> crate::Result { desktop::build( options, &self.app_settings, &mut self.available_targets, self.config_features.clone(), self.main_binary_name.as_deref(), + dirs.tauri, ) } fn dev, ExitReason) + Send + Sync + 'static>( &mut self, + config: &mut ConfigMetadata, mut options: Options, on_exit: F, + dirs: &Dirs, ) -> crate::Result<()> { let on_exit = Arc::new(on_exit); @@ -215,28 +213,37 @@ impl Interface for Rust { if options.no_watch { let (tx, rx) = sync_channel(1); self.run_dev(options, run_args, move |status, reason| { + on_exit(status, reason); tx.send(()).unwrap(); - on_exit(status, reason) })?; rx.recv().unwrap(); 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(&options.additional_watch_folders, &merge_configs, run) + self.run_dev_watcher( + config, + &options.additional_watch_folders, + &merge_configs, + |rust: &mut Rust, _config| { + let on_exit = on_exit.clone(); + rust.run_dev(options.clone(), run_args.clone(), move |status, reason| { + on_exit(status, reason) + }) + }, + dirs, + ) } } - fn mobile_dev crate::Result>>( + fn mobile_dev< + R: Fn(MobileOptions, &ConfigMetadata) -> crate::Result>, + >( &mut self, + config: &mut ConfigMetadata, mut options: MobileOptions, runner: R, + dirs: &Dirs, ) -> crate::Result<()> { let mut run_args = Vec::new(); dev_options( @@ -248,27 +255,36 @@ impl Interface for Rust { ); if options.no_watch { - runner(options)?; + runner(options, config)?; Ok(()) } else { self.watch( + config, WatcherOptions { 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>>( + fn watch crate::Result>>( &mut self, + 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(&options.additional_watch_folders, &merge_configs, run) + self.run_dev_watcher( + config, + &options.additional_watch_folders, + &merge_configs, + |_rust: &mut Rust, config| runner(config), + dirs, + ) } fn env(&self) -> HashMap<&str, String> { @@ -393,7 +409,7 @@ fn dev_options( mobile: bool, args: &mut Vec, run_args: &mut Vec, - features: &mut Option>, + features: &mut Vec, app_settings: &RustAppSettings, ) { let mut dev_args = Vec::new(); @@ -429,35 +445,25 @@ fn dev_options( }) .collect(); args.push("--no-default-features".into()); - if !enable_features.is_empty() { - features.get_or_insert(Vec::new()).extend(enable_features); - } + features.extend(enable_features); } } -// 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]) -> crate::Result> { - let tauri_path = tauri_dir(); - let workspace_path = get_workspace_dir()?; - +fn get_watch_folders( + additional_watch_folders: &[PathBuf], + tauri_dir: &Path, +) -> crate::Result> { // We always want to watch the main tauri folder. - let mut watch_folders = vec![tauri_path.to_path_buf()]; + 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() { dir.to_owned() } else { - tauri_path.join(dir) + tauri_dir.join(dir) }; let canonicalized = canonicalize(&path).ok(); @@ -470,43 +476,12 @@ fn get_watch_folders(additional_watch_folders: &[PathBuf]) -> crate::Result { - 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.to_string()); - watch_folders.push(p); - } - }; - } - } - Ok(watch_folders) } impl Rust { - pub fn build_options( - &self, - args: &mut Vec, - features: &mut Option>, - mobile: bool, - ) { - features - .get_or_insert(Vec::new()) - .push("tauri/custom-protocol".into()); + pub fn build_options(&self, args: &mut Vec, features: &mut Vec, mobile: bool) { + features.push("tauri/custom-protocol".into()); if mobile { args.push("--lib".into()); } else { @@ -530,22 +505,30 @@ impl Rust { .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: &mut ConfigMetadata, additional_watch_folders: &[PathBuf], merge_configs: &[&serde_json::Value], - run: Arc, + run: F, + dirs: &Dirs, ) -> crate::Result<()> { - let child = run(self)?; + let child = run(self, config)?; let process = Arc::new(Mutex::new(child)); let (tx, rx) = sync_channel(1); - let frontend_path = frontend_dir(); - let watch_folders = get_watch_folders(additional_watch_folders)?; + 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| { @@ -582,22 +565,21 @@ 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) { - if let Ok(config) = reload_config(merge_configs) { - let (manifest, modified) = - rewrite_manifest(config.lock().unwrap().as_ref().unwrap())?; - if modified { - *self.app_settings.manifest.lock().unwrap() = manifest; - // no need to run the watcher logic, the manifest was modified - // and it will trigger the watcher again - continue; - } + if is_configuration_file(self.app_settings.target_platform, event_path) + && reload_config(config, merge_configs, dirs.tauri).is_ok() + { + 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 + // and it will trigger the watcher again + continue; } } log::info!( "File {} changed. Rebuilding application...", - display_path(event_path.strip_prefix(frontend_path).unwrap_or(event_path)) + display_path(event_path.strip_prefix(dirs.frontend).unwrap_or(event_path)) ); let mut p = process.lock().unwrap(); @@ -610,7 +592,7 @@ impl Rust { break; } } - *p = run(self)?; + *p = run(self, config)?; } } } @@ -681,7 +663,7 @@ pub struct TomlWorkspaceField { #[derive(Clone, Debug, Deserialize)] struct WorkspaceSettings { /// the workspace members. - members: Option>, + // members: Option>, package: Option, } @@ -695,11 +677,13 @@ struct WorkspacePackageSettings { } #[derive(Clone, Debug, Deserialize)] +#[serde(rename_all = "kebab-case")] struct BinarySettings { name: String, /// This is from nightly: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#different-binary-name filename: Option, path: Option, + required_features: Option>, } impl BinarySettings { @@ -766,6 +750,7 @@ pub struct RustAppSettings { cargo_config: CargoConfig, target_triple: String, target_platform: TargetPlatform, + workspace_dir: PathBuf, } #[derive(Deserialize)] @@ -785,7 +770,7 @@ pub struct UpdaterConfig { } /// Install modes for the Windows update. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Default, Debug, PartialEq, Eq, Clone)] pub enum WindowsUpdateInstallMode { /// Specifies there's a basic UI during the installation process, including a final dialog box at the end. BasicUi, @@ -793,17 +778,12 @@ pub enum WindowsUpdateInstallMode { /// Requires admin privileges if the installer does. Quiet, /// Specifies unattended mode, which means the installation only shows a progress bar. + #[default] Passive, // to add more modes, we need to check if the updater relaunch makes sense // i.e. for a full UI mode, the user can also mark the installer to start the app } -impl Default for WindowsUpdateInstallMode { - fn default() -> Self { - Self::Passive - } -} - impl<'de> Deserialize<'de> for WindowsUpdateInstallMode { fn deserialize(deserializer: D) -> std::result::Result where @@ -849,6 +829,7 @@ impl AppSettings for RustAppSettings { options: &Options, config: &Config, features: &[String], + tauri_dir: &Path, ) -> crate::Result { let arch64bits = self.target_triple.starts_with("x86_64") || self.target_triple.starts_with("aarch64") @@ -879,6 +860,7 @@ impl AppSettings for RustAppSettings { self, features, config, + tauri_dir, config.bundle.clone(), updater_settings, arch64bits, @@ -923,8 +905,8 @@ impl AppSettings for RustAppSettings { Ok(settings) } - fn app_binary_path(&self, options: &Options) -> crate::Result { - let binaries = self.get_binaries()?; + fn app_binary_path(&self, options: &Options, tauri_dir: &Path) -> crate::Result { + let binaries = self.get_binaries(options, tauri_dir)?; let bin_name = binaries .iter() .find(|x| x.main()) @@ -932,7 +914,7 @@ impl AppSettings for RustAppSettings { .name(); let out_dir = self - .out_dir(options) + .out_dir(options, tauri_dir) .context("failed to get project out directory")?; let mut path = out_dir.join(bin_name); @@ -950,8 +932,8 @@ impl AppSettings for RustAppSettings { Ok(path) } - fn get_binaries(&self) -> crate::Result> { - let mut binaries: Vec = vec![]; + fn get_binaries(&self, options: &Options, tauri_dir: &Path) -> crate::Result> { + let mut binaries = Vec::new(); if let Some(bins) = &self.cargo_settings.bin { let default_run = self @@ -960,6 +942,15 @@ impl AppSettings for RustAppSettings { .clone() .unwrap_or_default(); for bin in bins { + if let Some(req_features) = &bin.required_features { + // Check if all required features are enabled. + if !req_features + .iter() + .all(|feat| options.features.contains(feat)) + { + continue; + } + } let file_name = bin.file_name(); let is_main = file_name == self.cargo_package_settings.name || file_name == default_run; binaries.push(BundleBinary::with_path( @@ -970,8 +961,6 @@ impl AppSettings for RustAppSettings { } } - let tauri_dir = tauri_dir(); - let mut binaries_paths = std::fs::read_dir(tauri_dir.join("src/bin")) .map(|dir| { dir @@ -1063,8 +1052,12 @@ impl AppSettings for RustAppSettings { } impl RustAppSettings { - pub fn new(config: &Config, manifest: Manifest, target: Option) -> crate::Result { - let tauri_dir = tauri_dir(); + pub fn new( + config: &Config, + manifest: Manifest, + target: Option, + tauri_dir: &Path, + ) -> crate::Result { let cargo_settings = CargoSettings::load(tauri_dir).context("failed to load Cargo settings")?; let cargo_package_settings = match &cargo_settings.package { Some(package_info) => package_info.clone(), @@ -1075,7 +1068,8 @@ impl RustAppSettings { } }; - let ws_package_settings = CargoSettings::load(&get_workspace_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); @@ -1170,6 +1164,7 @@ impl RustAppSettings { cargo_config, target_triple, target_platform, + workspace_dir, }) } @@ -1180,8 +1175,8 @@ impl RustAppSettings { .or_else(|| self.cargo_config.build().target()) } - pub fn out_dir(&self, options: &Options) -> crate::Result { - get_target_dir(self.target(options), options) + pub fn out_dir(&self, options: &Options, tauri_dir: &Path) -> crate::Result { + get_target_dir(self.target(options), options, tauri_dir) } } @@ -1189,12 +1184,29 @@ impl RustAppSettings { pub(crate) struct CargoMetadata { pub(crate) target_directory: PathBuf, pub(crate) workspace_root: PathBuf, + workspace_members: Vec, + packages: Vec, } -pub(crate) fn get_cargo_metadata() -> crate::Result { +#[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 { let output = Command::new("cargo") .args(["metadata", "--no-deps", "--format-version", "1"]) - .current_dir(tauri_dir()) + .current_dir(tauri_dir) .output() .map_err(|error| Error::CommandFailed { command: "cargo metadata --no-deps --format-version 1".to_string(), @@ -1211,16 +1223,66 @@ pub(crate) fn get_cargo_metadata() -> crate::Result { serde_json::from_slice(&output.stdout).context("failed to parse cargo metadata") } +/// Get the tauri project crate's dependencies that are inside the workspace +fn get_in_workspace_dependency_paths(tauri_dir: &Path) -> 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. -pub(crate) fn get_cargo_target_dir(args: &[String]) -> crate::Result { +pub(crate) fn get_cargo_target_dir(args: &[String], tauri_dir: &Path) -> crate::Result { let path = if let Some(target) = get_cargo_option(args, "--target-dir") { std::env::current_dir() .context("failed to get current directory")? .join(target) } else { - get_cargo_metadata() + get_cargo_metadata(tauri_dir) .context("failed to run 'cargo metadata' command to get target directory")? .target_directory }; @@ -1230,8 +1292,12 @@ pub(crate) fn get_cargo_target_dir(args: &[String]) -> crate::Result { /// This function determines the 'target' directory and suffixes it with the profile /// to determine where the compiled binary will be located. -fn get_target_dir(triple: Option<&str>, options: &Options) -> crate::Result { - let mut path = get_cargo_target_dir(&options.args)?; +fn get_target_dir( + triple: Option<&str>, + options: &Options, + tauri_dir: &Path, +) -> crate::Result { + let mut path = get_cargo_target_dir(&options.args, tauri_dir)?; if let Some(triple) = triple { path.push(triple); @@ -1256,9 +1322,9 @@ fn get_cargo_option<'a>(args: &'a [String], option: &'a str) -> Option<&'a str> } /// Executes `cargo metadata` to get the workspace directory. -pub fn get_workspace_dir() -> crate::Result { +pub fn get_workspace_dir(tauri_dir: &Path) -> crate::Result { Ok( - get_cargo_metadata() + get_cargo_metadata(tauri_dir) .context("failed to run 'cargo metadata' command to get workspace directory")? .workspace_root, ) @@ -1284,6 +1350,7 @@ fn tauri_config_to_bundle_settings( settings: &RustAppSettings, features: &[String], tauri_config: &Config, + tauri_dir: &Path, config: crate::helpers::config::BundleConfig, updater_config: Option, arch64bits: bool, @@ -1428,14 +1495,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(), @@ -1568,7 +1637,7 @@ fn tauri_config_to_bundle_settings( info_plist: { let mut src_plists = vec![]; - let path = tauri_dir().join("Info.plist"); + let path = tauri_dir.join("Info.plist"); if path.exists() { src_plists.push(path.into()); } @@ -1610,7 +1679,7 @@ fn tauri_config_to_bundle_settings( .unwrap() }) }), - license_file: config.license_file.map(|l| tauri_dir().join(l)), + license_file: config.license_file.map(|l| tauri_dir.join(l)), updater: updater_config, ..Default::default() }) @@ -1667,7 +1736,7 @@ mod tests { #[test] fn parse_cargo_option() { - let args = vec![ + let args = [ "build".into(), "--".into(), "--profile".into(), @@ -1747,7 +1816,7 @@ mod tests { #[test] fn parse_target_dir_from_opts() { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); let current_dir = std::env::current_dir().unwrap(); let options = Options { @@ -1764,11 +1833,11 @@ mod tests { }; assert_eq!( - get_target_dir(None, &options).unwrap(), + get_target_dir(None, &options, dirs.tauri).unwrap(), current_dir.join("path/to/some/dir/release") ); assert_eq!( - get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(), + get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(), current_dir .join("path/to/some/dir") .join("x86_64-pc-windows-msvc") @@ -1787,23 +1856,27 @@ mod tests { }; #[cfg(windows)] - assert!(get_target_dir(Some("x86_64-pc-windows-msvc"), &options) - .unwrap() - .ends_with("x86_64-pc-windows-msvc\\release")); + assert!( + get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri) + .unwrap() + .ends_with("x86_64-pc-windows-msvc\\release") + ); #[cfg(not(windows))] - assert!(get_target_dir(Some("x86_64-pc-windows-msvc"), &options) - .unwrap() - .ends_with("x86_64-pc-windows-msvc/release")); + assert!( + get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri) + .unwrap() + .ends_with("x86_64-pc-windows-msvc/release") + ); #[cfg(windows)] { std::env::set_var("CARGO_TARGET_DIR", "D:\\path\\to\\env\\dir"); assert_eq!( - get_target_dir(None, &options).unwrap(), + get_target_dir(None, &options, dirs.tauri).unwrap(), PathBuf::from("D:\\path\\to\\env\\dir\\release") ); assert_eq!( - get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(), + get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(), PathBuf::from("D:\\path\\to\\env\\dir\\x86_64-pc-windows-msvc\\release") ); } @@ -1812,11 +1885,11 @@ mod tests { { std::env::set_var("CARGO_TARGET_DIR", "/path/to/env/dir"); assert_eq!( - get_target_dir(None, &options).unwrap(), + get_target_dir(None, &options, dirs.tauri).unwrap(), PathBuf::from("/path/to/env/dir/release") ); assert_eq!( - get_target_dir(Some("x86_64-pc-windows-msvc"), &options).unwrap(), + get_target_dir(Some("x86_64-pc-windows-msvc"), &options, dirs.tauri).unwrap(), PathBuf::from("/path/to/env/dir/x86_64-pc-windows-msvc/release") ); } diff --git a/crates/tauri-cli/src/interface/rust/desktop.rs b/crates/tauri-cli/src/interface/rust/desktop.rs index f5edb4d6e..15cd503e6 100644 --- a/crates/tauri-cli/src/interface/rust/desktop.rs +++ b/crates/tauri-cli/src/interface/rust/desktop.rs @@ -12,7 +12,7 @@ use shared_child::SharedChild; use std::{ fs, io::{BufReader, ErrorKind, Write}, - path::PathBuf, + path::{Path, PathBuf}, process::{Command, ExitStatus, Stdio}, sync::{ atomic::{AtomicBool, Ordering}, @@ -158,9 +158,10 @@ pub fn build( available_targets: &mut Option>, config_features: Vec, main_binary_name: Option<&str>, + tauri_dir: &Path, ) -> crate::Result { - let out_dir = app_settings.out_dir(&options)?; - let bin_path = app_settings.app_binary_path(&options)?; + 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") { std::env::set_var("STATIC_VCRUNTIME", "true"); @@ -182,7 +183,7 @@ pub fn build( options.target.replace(triple.into()); let triple_out_dir = app_settings - .out_dir(&options) + .out_dir(&options, tauri_dir) .with_context(|| format!("failed to get {triple} out dir"))?; build_production_app(options, available_targets, config_features.clone()) @@ -262,9 +263,7 @@ fn cargo_command( build_cmd.args(&options.args); let mut features = config_features; - if let Some(f) = options.features { - features.extend(f); - } + features.extend(options.features); if !features.is_empty() { build_cmd.arg("--features"); build_cmd.arg(features.join(",")); @@ -335,7 +334,7 @@ fn rename_app( "" }; let new_path = bin_path.with_file_name(format!("{main_binary_name}{extension}")); - fs::rename(&bin_path, &new_path).fs_context("failed to rename app binary", bin_path.clone())?; + fs::rename(&bin_path, &new_path).fs_context("failed to rename app binary", bin_path)?; Ok(new_path) } else { Ok(bin_path) diff --git a/crates/tauri-cli/src/interface/rust/manifest.rs b/crates/tauri-cli/src/interface/rust/manifest.rs index 452aecaaa..40d307c2b 100644 --- a/crates/tauri-cli/src/interface/rust/manifest.rs +++ b/crates/tauri-cli/src/interface/rust/manifest.rs @@ -4,10 +4,7 @@ use crate::{ error::{Context, ErrorExt}, - helpers::{ - app_paths::tauri_dir, - config::{Config, PatternKind}, - }, + helpers::config::{Config, PatternKind}, }; use itertools::Itertools; @@ -272,8 +269,8 @@ fn inject_features( Ok(persist) } -pub fn rewrite_manifest(config: &Config) -> crate::Result<(Manifest, bool)> { - let manifest_path = tauri_dir().join("Cargo.toml"); +pub fn rewrite_manifest(config: &Config, tauri_dir: &Path) -> crate::Result<(Manifest, bool)> { + let manifest_path = tauri_dir.join("Cargo.toml"); let (mut manifest, original_manifest_str) = read_manifest(&manifest_path)?; let mut dependencies = Vec::new(); @@ -314,7 +311,7 @@ pub fn rewrite_manifest(config: &Config) -> crate::Result<(Manifest, bool)> { if persist && original_manifest_str != new_manifest_str { std::fs::write(&manifest_path, new_manifest_str) - .fs_context("failed to rewrite Cargo manifest", manifest_path.clone())?; + .fs_context("failed to rewrite Cargo manifest", &manifest_path)?; Ok(( Manifest { inner: manifest, @@ -354,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/lib.rs b/crates/tauri-cli/src/lib.rs index b473f63a7..186ef0ef8 100644 --- a/crates/tauri-cli/src/lib.rs +++ b/crates/tauri-cli/src/lib.rs @@ -65,17 +65,14 @@ impl FromStr for ConfigValue { let path = PathBuf::from(config); let raw = read_to_string(&path).fs_context("failed to read configuration file", path.clone())?; - match path.extension() { - Some(ext) if ext == "toml" => { - Ok(Self(::toml::from_str(&raw).with_context(|| { - format!("failed to parse config at {} as TOML", path.display()) - })?)) - } - Some(ext) if ext == "json5" => { - Ok(Self(::json5::from_str(&raw).with_context(|| { - format!("failed to parse config at {} as JSON5", path.display()) - })?)) - } + + match path.extension().and_then(|ext| ext.to_str()) { + Some("toml") => Ok(Self(::toml::from_str(&raw).with_context(|| { + format!("failed to parse config at {} as TOML", path.display()) + })?)), + Some("json5") => Ok(Self(::json5::from_str(&raw).with_context(|| { + format!("failed to parse config at {} as JSON5", path.display()) + })?)), // treat all other extensions as json _ => Ok(Self( // from tauri-utils/src/config/parse.rs: @@ -178,6 +175,13 @@ fn format_error(err: clap::Error) -> clap::Error { err.format(&mut app) } +fn get_verbosity(cli_verbose: u8) -> u8 { + std::env::var("TAURI_CLI_VERBOSITY") + .ok() + .and_then(|v| v.parse().ok()) + .unwrap_or(cli_verbose) +} + /// Run the Tauri CLI with the passed arguments, exiting if an error occurs. /// /// The passed arguments should have the binary argument(s) stripped out before being passed. @@ -221,16 +225,12 @@ where Ok(s) => s, Err(e) => e.exit(), }; - - let verbosity_number = std::env::var("TAURI_CLI_VERBOSITY") - .ok() - .and_then(|v| v.parse().ok()) - .unwrap_or(cli.verbose); // set the verbosity level so subsequent CLI calls (xcode-script, android-studio-script) refer to it + let verbosity_number = get_verbosity(cli.verbose); std::env::set_var("TAURI_CLI_VERBOSITY", verbosity_number.to_string()); let mut builder = Builder::from_default_env(); - let init_res = builder + if let Err(err) = builder .format_indent(Some(12)) .filter(None, verbosity_level(verbosity_number).to_level_filter()) // golbin spams an insane amount of really technical logs on the debug level so we're reducing one level @@ -250,7 +250,6 @@ where is_command_output = action == "stdout" || action == "stderr"; if !is_command_output { let style = Style::new().fg_color(Some(AnsiColor::Green.into())).bold(); - write!(f, "{style}{action:>12}{style:#} ")?; } } else { @@ -264,15 +263,13 @@ where if !is_command_output && log::log_enabled!(Level::Debug) { let style = Style::new().fg_color(Some(AnsiColor::Black.into())); - write!(f, "[{style}{}{style:#}] ", record.target())?; } writeln!(f, "{}", record.args()) }) - .try_init(); - - if let Err(err) = init_res { + .try_init() + { eprintln!("Failed to attach logger: {err}"); } @@ -305,7 +302,7 @@ fn verbosity_level(num: u8) -> Level { match num { 0 => Level::Info, 1 => Level::Debug, - 2.. => Level::Trace, + _ => Level::Trace, } } @@ -332,9 +329,15 @@ impl CommandExt for Command { self.stdin(os_pipe::dup_stdin()?); self.stdout(os_pipe::dup_stdout()?); self.stderr(os_pipe::dup_stderr()?); - let program = self.get_program().to_string_lossy().into_owned(); - log::debug!(action = "Running"; "Command `{} {}`", program, self.get_args().map(|arg| arg.to_string_lossy()).fold(String::new(), |acc, arg| format!("{acc} {arg}"))); + let program = self.get_program().to_string_lossy().into_owned(); + let args = self + .get_args() + .map(|a| a.to_string_lossy()) + .collect::>() + .join(" "); + + log::debug!(action = "Running"; "Command `{program} {args}`"); self.status() } @@ -342,8 +345,9 @@ impl CommandExt for Command { let program = self.get_program().to_string_lossy().into_owned(); let args = self .get_args() - .map(|arg| arg.to_string_lossy()) - .fold(String::new(), |acc, arg| format!("{acc} {arg}")); + .map(|a| a.to_string_lossy()) + .collect::>() + .join(" "); let cmdline = format!("{program} {args}"); log::debug!(action = "Running"; "Command `{cmdline}`"); @@ -359,16 +363,17 @@ impl CommandExt for Command { let stdout_lines_ = stdout_lines.clone(); std::thread::spawn(move || { let mut line = String::new(); - let mut lines = stdout_lines_.lock().unwrap(); - loop { - line.clear(); - match stdout.read_line(&mut line) { - Ok(0) => break, - Ok(_) => { - log::debug!(action = "stdout"; "{}", line.trim_end()); - lines.extend(line.as_bytes().to_vec()); + if let Ok(mut lines) = stdout_lines_.lock() { + loop { + line.clear(); + match stdout.read_line(&mut line) { + Ok(0) => break, + Ok(_) => { + log::debug!(action = "stdout"; "{}", line.trim_end()); + lines.extend(line.as_bytes()); + } + Err(_) => (), } - Err(_) => (), } } }); @@ -378,16 +383,17 @@ impl CommandExt for Command { let stderr_lines_ = stderr_lines.clone(); std::thread::spawn(move || { let mut line = String::new(); - let mut lines = stderr_lines_.lock().unwrap(); - loop { - line.clear(); - match stderr.read_line(&mut line) { - Ok(0) => break, - Ok(_) => { - log::debug!(action = "stderr"; "{}", line.trim_end()); - lines.extend(line.as_bytes().to_vec()); + if let Ok(mut lines) = stderr_lines_.lock() { + loop { + line.clear(); + match stderr.read_line(&mut line) { + Ok(0) => break, + Ok(_) => { + log::debug!(action = "stderr"; "{}", line.trim_end()); + lines.extend(line.as_bytes()); + } + Err(_) => (), } - Err(_) => (), } } }); @@ -423,4 +429,10 @@ mod tests { fn verify_cli() { Cli::command().debug_assert(); } + + #[test] + fn help_output_includes_build() { + let help = Cli::command().render_help().to_string(); + assert!(help.contains("Build")); + } } diff --git a/crates/tauri-cli/src/migrate/migrations/v1/config.rs b/crates/tauri-cli/src/migrate/migrations/v1/config.rs index 2d7d1be4b..3de72747d 100644 --- a/crates/tauri-cli/src/migrate/migrations/v1/config.rs +++ b/crates/tauri-cli/src/migrate/migrations/v1/config.rs @@ -104,7 +104,7 @@ fn migrate_config(config: &mut Value) -> Result { } // dangerousUseHttpScheme/useHttpsScheme - let dangerouse_use_http = tauri_config + let dangerous_use_http = tauri_config .get("security") .and_then(|w| w.as_object()) .and_then(|w| { @@ -120,7 +120,7 @@ fn migrate_config(config: &mut Value) -> Result { { for window in windows { if let Some(window) = window.as_object_mut() { - window.insert("useHttpsScheme".to_string(), (!dangerouse_use_http).into()); + window.insert("useHttpsScheme".to_string(), (!dangerous_use_http).into()); } } } diff --git a/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs b/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs index d4d03f38d..2092651d3 100644 --- a/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs +++ b/crates/tauri-cli/src/migrate/migrations/v1/manifest.rs @@ -21,7 +21,7 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> { migrate_manifest(&mut manifest)?; std::fs::write(&manifest_path, serialize_manifest(&manifest)) - .fs_context("failed to rewrite Cargo manifest", manifest_path.clone())?; + .fs_context("failed to rewrite Cargo manifest", &manifest_path)?; Ok(()) } diff --git a/crates/tauri-cli/src/migrate/migrations/v1/mod.rs b/crates/tauri-cli/src/migrate/migrations/v1/mod.rs index 14a9cd7c4..6372db7b5 100644 --- a/crates/tauri-cli/src/migrate/migrations/v1/mod.rs +++ b/crates/tauri-cli/src/migrate/migrations/v1/mod.rs @@ -2,35 +2,31 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use crate::{ - error::Context, - helpers::app_paths::{frontend_dir, tauri_dir}, - Result, -}; +use crate::{error::Context, helpers::app_paths::Dirs, Result}; mod config; mod frontend; mod manifest; -pub fn run() -> Result<()> { - let tauri_dir = tauri_dir(); - let frontend_dir = frontend_dir(); - - let mut migrated = config::migrate(tauri_dir).context("Could not migrate config")?; - manifest::migrate(tauri_dir).context("Could not migrate manifest")?; - let plugins = frontend::migrate(frontend_dir)?; +pub fn run(dirs: &Dirs) -> Result<()> { + let mut migrated = config::migrate(dirs.tauri).context("Could not migrate config")?; + manifest::migrate(dirs.tauri).context("Could not migrate manifest")?; + let plugins = frontend::migrate(dirs.frontend)?; migrated.plugins.extend(plugins); // Add plugins for plugin in migrated.plugins { - crate::add::run(crate::add::Options { - plugin: plugin.clone(), - branch: None, - tag: None, - rev: None, - no_fmt: false, - }) + crate::add::run( + crate::add::Options { + plugin: plugin.clone(), + branch: None, + tag: None, + rev: None, + no_fmt: false, + }, + dirs, + ) .with_context(|| format!("Could not migrate plugin '{plugin}'"))?; } diff --git a/crates/tauri-cli/src/migrate/migrations/v2_beta.rs b/crates/tauri-cli/src/migrate/migrations/v2_beta.rs index 6910ba116..dcb6e52c2 100644 --- a/crates/tauri-cli/src/migrate/migrations/v2_beta.rs +++ b/crates/tauri-cli/src/migrate/migrations/v2_beta.rs @@ -4,10 +4,7 @@ use crate::{ error::{Context, ErrorExt}, - helpers::{ - app_paths::{frontend_dir, tauri_dir}, - npm::PackageManager, - }, + helpers::{app_paths::Dirs, npm::PackageManager}, interface::rust::manifest::{read_manifest, serialize_manifest}, Result, }; @@ -16,22 +13,17 @@ use std::{fs::read_to_string, path::Path}; use toml_edit::{DocumentMut, Item, Table, TableLike, Value}; -pub fn run() -> Result<()> { - let frontend_dir = frontend_dir(); - let tauri_dir = tauri_dir(); - - let manifest_path = tauri_dir.join("Cargo.toml"); +pub fn run(dirs: &Dirs) -> Result<()> { + let manifest_path = dirs.tauri.join("Cargo.toml"); let (mut manifest, _) = read_manifest(&manifest_path)?; migrate_manifest(&mut manifest)?; - migrate_permissions(tauri_dir)?; + migrate_permissions(dirs.tauri)?; - migrate_npm_dependencies(frontend_dir)?; + migrate_npm_dependencies(dirs.frontend)?; - std::fs::write(&manifest_path, serialize_manifest(&manifest)).fs_context( - "failed to rewrite Cargo manifest", - manifest_path.to_path_buf(), - )?; + std::fs::write(&manifest_path, serialize_manifest(&manifest)) + .fs_context("failed to rewrite Cargo manifest", &manifest_path)?; Ok(()) } diff --git a/crates/tauri-cli/src/migrate/mod.rs b/crates/tauri-cli/src/migrate/mod.rs index 575a2516b..9a75089b0 100644 --- a/crates/tauri-cli/src/migrate/mod.rs +++ b/crates/tauri-cli/src/migrate/mod.rs @@ -4,10 +4,7 @@ use crate::{ error::{bail, Context, ErrorExt}, - helpers::{ - app_paths::tauri_dir, - cargo_manifest::{crate_version, CargoLock, CargoManifest}, - }, + helpers::cargo_manifest::{crate_version, CargoLock, CargoManifest}, interface::rust::get_workspace_dir, Result, }; @@ -17,22 +14,20 @@ use std::{fs::read_to_string, str::FromStr}; mod migrations; pub fn command() -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); - let tauri_dir = tauri_dir(); - - let manifest_contents = read_to_string(tauri_dir.join("Cargo.toml")).fs_context( + let manifest_contents = read_to_string(dirs.tauri.join("Cargo.toml")).fs_context( "failed to read Cargo manifest", - tauri_dir.join("Cargo.toml"), + dirs.tauri.join("Cargo.toml"), )?; let manifest = toml::from_str::(&manifest_contents).with_context(|| { format!( "failed to parse Cargo manifest {}", - tauri_dir.join("Cargo.toml").display() + dirs.tauri.join("Cargo.toml").display() ) })?; - let workspace_dir = get_workspace_dir()?; + let workspace_dir = get_workspace_dir(dirs.tauri)?; let lock_path = workspace_dir.join("Cargo.lock"); let lock = if lock_path.exists() { let lockfile_contents = @@ -44,19 +39,19 @@ pub fn command() -> Result<()> { None }; - let tauri_version = crate_version(tauri_dir, Some(&manifest), lock.as_ref(), "tauri") + let tauri_version = crate_version(dirs.tauri, Some(&manifest), lock.as_ref(), "tauri") .version .context("failed to get tauri version")?; let tauri_version = semver::Version::from_str(&tauri_version) .with_context(|| format!("failed to parse tauri version {tauri_version}"))?; if tauri_version.major == 1 { - migrations::v1::run().context("failed to migrate from v1")?; + migrations::v1::run(&dirs).context("failed to migrate from v1")?; } else if tauri_version.major == 2 { if let Some((pre, _number)) = tauri_version.pre.as_str().split_once('.') { match pre { "beta" => { - migrations::v2_beta::run().context("failed to migrate from v2 beta")?; + migrations::v2_beta::run(&dirs).context("failed to migrate from v2 beta")?; } "alpha" => { bail!( 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 c3dfdff4b..ce1d6ba8e 100644 --- a/crates/tauri-cli/src/mobile/android/android_studio_script.rs +++ b/crates/tauri-cli/src/mobile/android/android_studio_script.rs @@ -5,7 +5,7 @@ use super::{detect_target_ok, ensure_init, env, get_app, get_config, read_options, MobileTarget}; use crate::{ error::{Context, ErrorExt}, - helpers::config::{get as get_tauri_config, reload as reload_tauri_config}, + helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config}, interface::{AppInterface, Interface}, mobile::CliOptions, Error, Result, @@ -38,7 +38,7 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); let profile = if options.release { Profile::Release @@ -46,41 +46,32 @@ pub fn command(options: Options) -> Result<()> { Profile::Debug }; - let (tauri_config, cli_options) = { - let tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, &[])?; - let cli_options = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - read_options(tauri_config_) - }; + let mut tauri_config = get_tauri_config(tauri_utils::platform::Target::Android, &[], dirs.tauri)?; + let cli_options = read_options(&tauri_config); - let tauri_config = if cli_options.config.is_empty() { - tauri_config - } else { - // reload config with merges from the android dev|build script - reload_tauri_config( - &cli_options - .config - .iter() - .map(|conf| &conf.0) - .collect::>(), - )? - }; - - (tauri_config, cli_options) + if !cli_options.config.is_empty() { + // reload config with merges from the android dev|build script + reload_tauri_config( + &mut tauri_config, + &cli_options + .config + .iter() + .map(|conf| &conf.0) + .collect::>(), + dirs.tauri, + )? }; let (config, metadata) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); let (config, metadata) = get_config( &get_app( MobileTarget::Android, - tauri_config_, - &AppInterface::new(tauri_config_, None)?, + &tauri_config, + &AppInterface::new(&tauri_config, None, dirs.tauri)?, + dirs.tauri, ), - tauri_config_, - None, + &tauri_config, + &[], &cli_options, ); (config, metadata) @@ -95,7 +86,8 @@ pub fn command(options: Options) -> Result<()> { )?; if !cli_options.config.is_empty() { - crate::helpers::config::merge_with( + crate::helpers::config::merge_config_with( + &mut tauri_config, &cli_options .config .iter() @@ -107,16 +99,7 @@ pub fn command(options: Options) -> Result<()> { let env = env(std::env::var("CI").is_ok())?; if cli_options.dev { - let dev_url = tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .dev_url - .clone(); - - if let Some(url) = dev_url { + if let Some(url) = &tauri_config.build.dev_url { let localhost = match url.host() { Some(url::Host::Domain(d)) => d == "localhost", Some(url::Host::Ipv4(i)) => i == std::net::Ipv4Addr::LOCALHOST, diff --git a/crates/tauri-cli/src/mobile/android/build.rs b/crates/tauri-cli/src/mobile/android/build.rs index a8f5ff2d2..7b85ef47d 100644 --- a/crates/tauri-cli/src/mobile/android/build.rs +++ b/crates/tauri-cli/src/mobile/android/build.rs @@ -10,12 +10,12 @@ use crate::{ build::Options as BuildOptions, error::Context, helpers::{ - app_paths::tauri_dir, - config::{get as get_tauri_config, ConfigHandle}, + app_paths::Dirs, + config::{get_config as get_tauri_config, ConfigMetadata}, flock, }, interface::{AppInterface, Interface, Options as InterfaceOptions}, - mobile::{write_options, CliOptions, TargetDevice}, + mobile::{android::generate_tauri_properties, write_options, CliOptions, TargetDevice}, ConfigValue, Error, Result, }; use clap::{ArgAction, Parser}; @@ -27,6 +27,7 @@ use cargo_mobile2::{ }; use std::env::set_current_dir; +use std::path::Path; #[derive(Debug, Clone, Parser)] #[clap( @@ -48,7 +49,7 @@ pub struct Options { pub targets: Option>, /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file /// /// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts. @@ -63,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, @@ -116,8 +119,25 @@ pub struct BuiltApplication { } pub fn command(options: Options, noise_level: NoiseLevel) -> Result { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); + let tauri_config = get_tauri_config( + tauri_utils::platform::Target::Android, + &options + .config + .iter() + .map(|conf| &conf.0) + .collect::>(), + dirs.tauri, + )?; + run(options, noise_level, &dirs, &tauri_config) +} +pub fn run( + options: Options, + noise_level: NoiseLevel, + dirs: &Dirs, + tauri_config: &ConfigMetadata, +) -> Result { delete_codegen_vars(); let mut build_options: BuildOptions = options.clone().into(); @@ -133,26 +153,15 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result>(), - )?; let (interface, config, metadata) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - - let interface = AppInterface::new(tauri_config_, build_options.target.clone())?; + 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); + let app = get_app(MobileTarget::Android, tauri_config, &interface, dirs.tauri); let (config, metadata) = get_config( &app, - tauri_config_, - build_options.features.as_ref(), + tauri_config, + &build_options.features, &Default::default(), ); (interface, config, metadata) @@ -164,11 +173,10 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result Result Result 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 { @@ -246,7 +258,7 @@ fn run_build( }; let app_settings = interface.app_settings(); - let out_dir = app_settings.out_dir(&interface_options)?; + let out_dir = app_settings.out_dir(&interface_options, tauri_dir)?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; let cli_options = CliOptions { @@ -258,11 +270,11 @@ fn run_build( config: build_options.config, target_device: options.target_device.clone(), }; - let handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?; + let handle = write_options(tauri_config, cli_options)?; - inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?; + inject_resources(config, tauri_config)?; - let apk_outputs = if options.apk.unwrap_or_default() { + let apk_outputs = if options.apk { apk::build( config, env, @@ -276,7 +288,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 350d62596..a4cfaacd4 100644 --- a/crates/tauri-cli/src/mobile/android/dev.rs +++ b/crates/tauri-cli/src/mobile/android/dev.rs @@ -10,14 +10,14 @@ use crate::{ dev::Options as DevOptions, error::{Context, ErrorExt}, helpers::{ - app_paths::tauri_dir, - config::{get as get_tauri_config, ConfigHandle}, + app_paths::Dirs, + config::{get_config as get_tauri_config, ConfigMetadata}, flock, }, interface::{AppInterface, Interface, MobileOptions, Options as InterfaceOptions}, mobile::{ - use_network_address_for_dev_url, write_options, CliOptions, DevChild, DevHost, DevProcess, - TargetDevice, + android::generate_tauri_properties, use_network_address_for_dev_url, write_options, CliOptions, + DevChild, DevHost, DevProcess, TargetDevice, }, ConfigValue, Error, Result, }; @@ -45,7 +45,7 @@ use std::{env::set_current_dir, net::Ipv4Addr, path::PathBuf}; pub struct Options { /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// Exit on panic #[clap(short, long)] exit_on_panic: bool, @@ -131,16 +131,16 @@ impl From for DevOptions { } pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); - let result = run_command(options, noise_level); + let result = run_command(options, noise_level, dirs); if result.is_err() { crate::dev::kill_before_dev_process(); } result } -fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { +fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<()> { delete_codegen_vars(); // setup env additions before calling env() if let Some(root_certificate_path) = &options.root_certificate_path { @@ -160,6 +160,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { .iter() .map(|conf| &conf.0) .collect::>(), + dirs.tauri, )?; let env = env(false)?; @@ -183,23 +184,19 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { dev_options.target = Some(target_triple); let (interface, config, metadata) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + let interface = AppInterface::new(&tauri_config, dev_options.target.clone(), dirs.tauri)?; - let interface = AppInterface::new(tauri_config_, dev_options.target.clone())?; - - let app = get_app(MobileTarget::Android, tauri_config_, &interface); + let app = get_app(MobileTarget::Android, &tauri_config, &interface, dirs.tauri); let (config, metadata) = get_config( &app, - tauri_config_, + &tauri_config, dev_options.features.as_ref(), &Default::default(), ); (interface, config, metadata) }; - let tauri_path = tauri_dir(); - set_current_dir(tauri_path).context("failed to set current directory to Tauri directory")?; + set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?; ensure_init( &tauri_config, @@ -218,6 +215,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { &config, &metadata, noise_level, + &dirs, ) } @@ -226,12 +224,13 @@ fn run_dev( mut interface: AppInterface, options: Options, mut dev_options: DevOptions, - tauri_config: ConfigHandle, + mut tauri_config: ConfigMetadata, device: Option, mut env: Env, config: &AndroidConfig, metadata: &AndroidMetadata, noise_level: NoiseLevel, + dirs: &Dirs, ) -> Result<()> { // when --host is provided or running on a physical device or resolving 0.0.0.0 we must use the network IP if options.host.0.is_some() @@ -239,25 +238,22 @@ fn run_dev( .as_ref() .map(|device| !device.serial_no().starts_with("emulator")) .unwrap_or(false) - || tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .dev_url - .as_ref() - .is_some_and(|url| { - matches!( - url.host(), - Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED - ) - }) + || tauri_config.build.dev_url.as_ref().is_some_and(|url| { + matches!( + url.host(), + Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED + ) + }) { - use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?; + use_network_address_for_dev_url( + &mut tauri_config, + &mut dev_options, + options.force_ip_prompt, + dirs.tauri, + )?; } - crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; + crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, dirs)?; let interface_options = InterfaceOptions { debug: !dev_options.release_mode, @@ -266,11 +262,13 @@ fn run_dev( }; let app_settings = interface.app_settings(); - let out_dir = app_settings.out_dir(&interface_options)?; + let out_dir = app_settings.out_dir(&interface_options, dirs.tauri)?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("android"), "Android")?; configure_cargo(&mut env, config)?; + generate_tauri_properties(config, &tauri_config, true)?; + let installed_targets = crate::interface::rust::installation::installed_targets().unwrap_or_default(); @@ -305,6 +303,7 @@ fn run_dev( let open = options.open; interface.mobile_dev( + &mut tauri_config, MobileOptions { debug: !options.release_mode, features: options.features, @@ -313,7 +312,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(), @@ -327,9 +326,9 @@ fn run_dev( }), }; - let _handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?; + let _handle = write_options(tauri_config, cli_options)?; - inject_resources(config, tauri_config.lock().unwrap().as_ref().unwrap())?; + inject_resources(config, tauri_config)?; if open { open_and_wait(config, &env) @@ -345,6 +344,7 @@ fn run_dev( open_and_wait(config, &env) } }, + dirs, ) } diff --git a/crates/tauri-cli/src/mobile/android/mod.rs b/crates/tauri-cli/src/mobile/android/mod.rs index 9a0475278..8ea6490d0 100644 --- a/crates/tauri-cli/src/mobile/android/mod.rs +++ b/crates/tauri-cli/src/mobile/android/mod.rs @@ -18,6 +18,7 @@ use cargo_mobile2::{ util::prompt, }; use clap::{Parser, Subcommand}; +use semver::Version; use std::{ env::set_var, fs::{create_dir, create_dir_all, read_dir, write}, @@ -105,16 +106,13 @@ enum Commands { pub fn command(cli: Cli, verbosity: u8) -> Result<()> { let noise_level = NoiseLevel::from_occurrences(verbosity as u64); match cli.command { - Commands::Init(options) => { - crate::helpers::app_paths::resolve(); - init_command( - MobileTarget::Android, - options.ci, - false, - options.skip_targets_install, - options.config, - )? - } + Commands::Init(options) => init_command( + MobileTarget::Android, + options.ci, + false, + options.skip_targets_install, + options.config, + )?, Commands::Dev(options) => dev::command(options, noise_level)?, Commands::Build(options) => build::command(options, noise_level).map(|_| ())?, Commands::Run(options) => run::command(options, noise_level)?, @@ -127,19 +125,14 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> { pub fn get_config( app: &App, config: &TauriConfig, - features: Option<&Vec>, + features: &[String], cli_options: &CliOptions, ) -> (AndroidConfig, AndroidMetadata) { let mut android_options = cli_options.clone(); - if let Some(features) = features { - android_options - .features - .get_or_insert(Vec::new()) - .extend_from_slice(features); - } + android_options.features.extend_from_slice(features); let raw = RawAndroidConfig { - features: android_options.features.clone(), + features: Some(android_options.features.clone()), logcat_filter_specs: vec![ "RustStdoutStderr".into(), format!( @@ -160,7 +153,7 @@ pub fn get_config( let metadata = AndroidMetadata { supported: true, cargo_args: Some(android_options.args), - features: android_options.features, + features: Some(android_options.features), ..Default::default() }; @@ -256,8 +249,8 @@ fn ensure_java() -> Result<()> { fn ensure_sdk(non_interactive: bool) -> Result<()> { let android_home = std::env::var_os("ANDROID_HOME") - .map(PathBuf::from) - .or_else(|| std::env::var_os("ANDROID_SDK_ROOT").map(PathBuf::from)); + .or_else(|| std::env::var_os("ANDROID_SDK_ROOT")) + .map(PathBuf::from); if !android_home.as_ref().is_some_and(|v| v.exists()) { log::info!( "ANDROID_HOME {}, trying to locate Android SDK...", @@ -353,8 +346,8 @@ fn ensure_sdk(non_interactive: bool) -> Result<()> { fn ensure_ndk(non_interactive: bool) -> Result<()> { // re-evaluate ANDROID_HOME let android_home = std::env::var_os("ANDROID_HOME") + .or_else(|| std::env::var_os("ANDROID_SDK_ROOT")) .map(PathBuf::from) - .or_else(|| std::env::var_os("ANDROID_SDK_ROOT").map(PathBuf::from)) .context("Failed to locate Android SDK")?; let mut installed_ndks = read_dir(android_home.join("ndk")) .map(|dir| { @@ -620,3 +613,66 @@ fn configure_cargo(env: &mut Env, config: &AndroidConfig) -> Result<()> { Ok(()) } + +fn generate_tauri_properties( + config: &AndroidConfig, + tauri_config: &TauriConfig, + dev: bool, +) -> Result<()> { + let app_tauri_properties_path = config.project_dir().join("app").join("tauri.properties"); + + let mut app_tauri_properties = Vec::new(); + if let Some(version) = tauri_config.version.as_ref() { + app_tauri_properties.push(format!("tauri.android.versionName={version}")); + if tauri_config.bundle.android.auto_increment_version_code && !dev { + let last_version_code = std::fs::read_to_string(&app_tauri_properties_path) + .ok() + .and_then(|content| { + content + .lines() + .find(|line| line.starts_with("tauri.android.versionCode=")) + .and_then(|line| line.split('=').nth(1)) + .and_then(|s| s.trim().parse::().ok()) + }); + let new_version_code = last_version_code.map(|v| v.saturating_add(1)).unwrap_or(1); + app_tauri_properties.push(format!("tauri.android.versionCode={new_version_code}")); + } else if let Some(version_code) = tauri_config.bundle.android.version_code.as_ref() { + app_tauri_properties.push(format!("tauri.android.versionCode={version_code}")); + } else if let Ok(version) = Version::parse(version) { + let mut version_code = version.major * 1000000 + version.minor * 1000 + version.patch; + + if dev { + version_code = version_code.clamp(1, 2100000000); + } + + if version_code == 0 { + crate::error::bail!( + "You must change the `version` in `tauri.conf.json`. The default value `0.0.0` is not allowed for Android package and must be at least `0.0.1`." + ); + } else if version_code > 2100000000 { + crate::error::bail!( + "Invalid version code {}. Version code must be between 1 and 2100000000. You must change the `version` in `tauri.conf.json`.", + version_code + ); + } + + app_tauri_properties.push(format!("tauri.android.versionCode={version_code}")); + } + } + + if !app_tauri_properties.is_empty() { + let app_tauri_properties_content = format!( + "// THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.\n{}", + app_tauri_properties.join("\n") + ); + if std::fs::read_to_string(&app_tauri_properties_path) + .map(|o| o != app_tauri_properties_content) + .unwrap_or(true) + { + write(&app_tauri_properties_path, app_tauri_properties_content) + .context("failed to write tauri.properties")?; + } + } + + Ok(()) +} diff --git a/crates/tauri-cli/src/mobile/android/run.rs b/crates/tauri-cli/src/mobile/android/run.rs index 9c276c4d9..c07c6ba6d 100644 --- a/crates/tauri-cli/src/mobile/android/run.rs +++ b/crates/tauri-cli/src/mobile/android/run.rs @@ -13,6 +13,7 @@ use std::path::PathBuf; use super::{configure_cargo, device_prompt, env}; use crate::{ error::Context, + helpers::config::ConfigMetadata, interface::{DevProcess, Interface, WatcherOptions}, mobile::{DevChild, TargetDevice}, ConfigValue, Result, @@ -29,7 +30,7 @@ pub struct Options { pub release: bool, /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file /// /// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts. @@ -77,7 +78,17 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { } }; - let mut built_application = super::build::command( + let dirs = crate::helpers::app_paths::resolve_dirs(); + let mut tauri_config = crate::helpers::config::get_config( + tauri_utils::platform::Target::Android, + &options + .config + .iter() + .map(|conf| &conf.0) + .collect::>(), + dirs.tauri, + )?; + let mut built_application = super::build::run( super::build::Options { debug: !options.release, targets: device.as_ref().map(|d| { @@ -90,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, @@ -102,6 +114,8 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }), }, noise_level, + &dirs, + &tauri_config, )?; configure_cargo(&mut env, &built_application.config)?; @@ -111,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, @@ -136,14 +150,16 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }; if options.no_watch { - runner()?; + runner(&tauri_config)?; } else { built_application.interface.watch( + &mut tauri_config, WatcherOptions { config: options.config, additional_watch_folders: options.additional_watch_folders, }, runner, + &dirs, )?; } } diff --git a/crates/tauri-cli/src/mobile/init.rs b/crates/tauri-cli/src/mobile/init.rs index 2a3cab0b4..f187b9f12 100644 --- a/crates/tauri-cli/src/mobile/init.rs +++ b/crates/tauri-cli/src/mobile/init.rs @@ -4,7 +4,8 @@ use super::{get_app, Target}; use crate::{ - helpers::{config::get as get_tauri_config, template::JsonMap}, + helpers::app_paths::Dirs, + helpers::{config::get_config as get_tauri_config, template::JsonMap}, interface::{AppInterface, Interface}, ConfigValue, Result, }; @@ -29,6 +30,7 @@ pub fn command( skip_targets_install: bool, config: Vec, ) -> Result<()> { + let dirs = crate::helpers::app_paths::resolve_dirs(); let wrapper = TextWrapper::default(); exec( @@ -38,30 +40,31 @@ pub fn command( reinstall_deps, skip_targets_install, config, + dirs, )?; 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, ) -> Result { let tauri_config = get_tauri_config( target.platform_target(), &config.iter().map(|conf| &conf.0).collect::>(), + dirs.tauri, )?; - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - let app = get_app( target, - tauri_config_, - &AppInterface::new(tauri_config_, None)?, + &tauri_config, + &AppInterface::new(&tauri_config, None, dirs.tauri)?, + dirs.tauri, ); let (handlebars, mut map) = handlebars(&app); @@ -135,7 +138,7 @@ pub fn exec( Target::Android => { let _env = super::android::env(non_interactive)?; let (config, metadata) = - super::android::get_config(&app, tauri_config_, None, &Default::default()); + super::android::get_config(&app, &tauri_config, &[], &Default::default()); map.insert("android", &config); super::android::project::gen( &config, @@ -150,10 +153,10 @@ pub fn exec( // Generate Xcode project Target::Ios => { let (config, metadata) = - super::ios::get_config(&app, tauri_config_, None, &Default::default())?; + super::ios::get_config(&app, &tauri_config, &[], &Default::default(), dirs.tauri)?; map.insert("apple", &config); super::ios::project::gen( - tauri_config_, + &tauri_config, &config, &metadata, (handlebars, map), diff --git a/crates/tauri-cli/src/mobile/ios/build.rs b/crates/tauri-cli/src/mobile/ios/build.rs index 9f4aab42c..5ad7e58d5 100644 --- a/crates/tauri-cli/src/mobile/ios/build.rs +++ b/crates/tauri-cli/src/mobile/ios/build.rs @@ -11,8 +11,8 @@ use crate::{ build::Options as BuildOptions, error::{Context, ErrorExt}, helpers::{ - app_paths::tauri_dir, - config::{get as get_tauri_config, ConfigHandle}, + app_paths::Dirs, + config::{get_config as get_tauri_config, ConfigMetadata}, flock, plist::merge_plist, }, @@ -60,7 +60,7 @@ pub struct Options { pub targets: Option>, /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file /// /// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts. @@ -168,8 +168,11 @@ pub struct BuiltApplication { } pub fn command(options: Options, noise_level: NoiseLevel) -> Result { - crate::helpers::app_paths::resolve(); + 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,26 +192,24 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result>(), + dirs.tauri, )?; let (interface, mut config) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - - let interface = AppInterface::new(tauri_config_, build_options.target.clone())?; + 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); + let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); let (config, _metadata) = get_config( &app, - tauri_config_, - build_options.features.as_ref(), + &tauri_config, + &build_options.features, &Default::default(), + dirs.tauri, )?; (interface, config) }; - let tauri_path = tauri_dir(); - set_current_dir(tauri_path).context("failed to set current directory")?; + set_current_dir(dirs.tauri).context("failed to set current directory")?; ensure_init( &tauri_config, @@ -217,7 +218,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result Result Result Result Result { let profile = if options.debug { Profile::Debug @@ -367,15 +362,18 @@ fn run_build( Profile::Release }; - crate::build::setup(interface, &mut build_options, tauri_config.clone(), true)?; + crate::build::setup(interface, &mut build_options, &tauri_config, dirs, true)?; let app_settings = interface.app_settings(); - let out_dir = app_settings.out_dir(&InterfaceOptions { - debug: build_options.debug, - target: build_options.target.clone(), - args: build_options.args.clone(), - ..Default::default() - })?; + let out_dir = app_settings.out_dir( + &InterfaceOptions { + debug: build_options.debug, + target: build_options.target.clone(), + args: build_options.args.clone(), + ..Default::default() + }, + dirs.tauri, + )?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; let cli_options = CliOptions { @@ -387,7 +385,7 @@ fn run_build( config: build_options.config.clone(), target_device: options.target_device.clone(), }; - let handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?; + let handle = write_options(&tauri_config, cli_options)?; if options.open { return Ok(handle); diff --git a/crates/tauri-cli/src/mobile/ios/dev.rs b/crates/tauri-cli/src/mobile/ios/dev.rs index 45cd44f5b..397875ac2 100644 --- a/crates/tauri-cli/src/mobile/ios/dev.rs +++ b/crates/tauri-cli/src/mobile/ios/dev.rs @@ -10,8 +10,8 @@ use crate::{ dev::Options as DevOptions, error::{Context, ErrorExt}, helpers::{ - app_paths::tauri_dir, - config::{get as get_tauri_config, ConfigHandle}, + app_paths::Dirs, + config::{get_config as get_tauri_config, ConfigMetadata}, flock, plist::merge_plist, }, @@ -54,7 +54,7 @@ environment variable to determine whether the public network should be used or n pub struct Options { /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// Exit on panic #[clap(short, long)] exit_on_panic: bool, @@ -138,16 +138,16 @@ impl From for DevOptions { } pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); - let result = run_command(options, noise_level); + let result = run_command(options, noise_level, dirs); if result.is_err() { crate::dev::kill_before_dev_process(); } result } -fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { +fn run_command(options: Options, noise_level: NoiseLevel, dirs: Dirs) -> Result<()> { // setup env additions before calling env() if let Some(root_certificate_path) = &options.root_certificate_path { std::env::set_var( @@ -186,26 +186,24 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { let tauri_config = get_tauri_config( tauri_utils::platform::Target::Ios, &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, )?; let (interface, config) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); + let interface = AppInterface::new(&tauri_config, Some(target_triple), dirs.tauri)?; - let interface = AppInterface::new(tauri_config_, Some(target_triple))?; - - let app = get_app(MobileTarget::Ios, tauri_config_, &interface); + let app = get_app(MobileTarget::Ios, &tauri_config, &interface, dirs.tauri); let (config, _metadata) = get_config( &app, - tauri_config_, - dev_options.features.as_ref(), + &tauri_config, + &dev_options.features, &Default::default(), + dirs.tauri, )?; (interface, config) }; - let tauri_path = tauri_dir(); - set_current_dir(tauri_path).context("failed to set current directory to Tauri directory")?; + set_current_dir(dirs.tauri).context("failed to set current directory to Tauri directory")?; ensure_init( &tauri_config, @@ -214,28 +212,20 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { MobileTarget::Ios, false, )?; - inject_resources(&config, tauri_config.lock().unwrap().as_ref().unwrap())?; + inject_resources(&config, &tauri_config)?; let info_plist_path = config .project_dir() .join(config.scheme()) .join("Info.plist"); let mut src_plists = vec![info_plist_path.clone().into()]; - if tauri_path.join("Info.plist").exists() { - src_plists.push(tauri_path.join("Info.plist").into()); + if dirs.tauri.join("Info.plist").exists() { + src_plists.push(dirs.tauri.join("Info.plist").into()); } - if tauri_path.join("Info.ios.plist").exists() { - src_plists.push(tauri_path.join("Info.ios.plist").into()); + if dirs.tauri.join("Info.ios.plist").exists() { + src_plists.push(dirs.tauri.join("Info.ios.plist").into()); } - if let Some(info_plist) = &tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .bundle - .ios - .info_plist - { + if let Some(info_plist) = &tauri_config.bundle.ios.info_plist { src_plists.push(info_plist.clone().into()); } let merged_info_plist = merge_plist(src_plists)?; @@ -274,6 +264,7 @@ fn run_command(options: Options, noise_level: NoiseLevel) -> Result<()> { env, &config, noise_level, + &dirs, ) } @@ -282,11 +273,12 @@ fn run_dev( mut interface: AppInterface, options: Options, mut dev_options: DevOptions, - tauri_config: ConfigHandle, + mut tauri_config: ConfigMetadata, device: Option, env: Env, config: &AppleConfig, noise_level: NoiseLevel, + dirs: &Dirs, ) -> Result<()> { // when --host is provided or running on a physical device or resolving 0.0.0.0 we must use the network IP if options.host.0.is_some() @@ -294,38 +286,39 @@ fn run_dev( .as_ref() .map(|device| !matches!(device.kind(), DeviceKind::Simulator)) .unwrap_or(false) - || tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .dev_url - .as_ref() - .is_some_and(|url| { - matches!( + || tauri_config.build.dev_url.as_ref().is_some_and(|url| { + matches!( url.host(), Some(Host::Ipv4(i)) if i == Ipv4Addr::UNSPECIFIED - ) - }) + ) + }) { - use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?; + use_network_address_for_dev_url( + &mut tauri_config, + &mut dev_options, + options.force_ip_prompt, + dirs.tauri, + )?; } - crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; + crate::dev::setup(&interface, &mut dev_options, &mut tauri_config, &dirs)?; let app_settings = interface.app_settings(); - let out_dir = app_settings.out_dir(&InterfaceOptions { - debug: !dev_options.release_mode, - target: dev_options.target.clone(), - ..Default::default() - })?; + let out_dir = app_settings.out_dir( + &InterfaceOptions { + debug: !dev_options.release_mode, + target: dev_options.target.clone(), + ..Default::default() + }, + dirs.tauri, + )?; let _lock = flock::open_rw(out_dir.join("lock").with_extension("ios"), "iOS")?; let set_host = options.host.0.is_some(); let open = options.open; interface.mobile_dev( + &mut tauri_config, MobileOptions { debug: true, features: options.features, @@ -334,7 +327,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(), @@ -344,7 +337,7 @@ fn run_dev( config: dev_options.config.clone(), target_device: None, }; - let _handle = write_options(tauri_config.lock().unwrap().as_ref().unwrap(), cli_options)?; + let _handle = write_options(tauri_config, cli_options)?; let open_xcode = || { if !set_host { @@ -371,6 +364,7 @@ fn run_dev( open_xcode() } }, + &dirs, ) } diff --git a/crates/tauri-cli/src/mobile/ios/mod.rs b/crates/tauri-cli/src/mobile/ios/mod.rs index ca4aade41..6c0e0af87 100644 --- a/crates/tauri-cli/src/mobile/ios/mod.rs +++ b/crates/tauri-cli/src/mobile/ios/mod.rs @@ -30,8 +30,7 @@ use super::{ use crate::{ error::{Context, ErrorExt}, helpers::{ - app_paths::tauri_dir, - config::{BundleResources, Config as TauriConfig, ConfigHandle}, + config::{BundleResources, Config as TauriConfig, ConfigMetadata}, pbxproj, strip_semver_prerelease_tag, }, ConfigValue, Error, Result, @@ -40,7 +39,7 @@ use crate::{ use std::{ env::{set_var, var_os}, fs::create_dir_all, - path::PathBuf, + path::Path, str::FromStr, thread::sleep, time::Duration, @@ -104,16 +103,13 @@ enum Commands { pub fn command(cli: Cli, verbosity: u8) -> Result<()> { let noise_level = NoiseLevel::from_occurrences(verbosity as u64); match cli.command { - Commands::Init(options) => { - crate::helpers::app_paths::resolve(); - init_command( - MobileTarget::Ios, - options.ci, - options.reinstall_deps, - options.skip_targets_install, - options.config, - )? - } + Commands::Init(options) => init_command( + MobileTarget::Ios, + options.ci, + options.reinstall_deps, + options.skip_targets_install, + options.config, + )?, Commands::Dev(options) => dev::command(options, noise_level)?, Commands::Build(options) => build::command(options, noise_level).map(|_| ())?, Commands::Run(options) => run::command(options, noise_level)?, @@ -126,16 +122,12 @@ pub fn command(cli: Cli, verbosity: u8) -> Result<()> { pub fn get_config( app: &App, tauri_config: &TauriConfig, - features: Option<&Vec>, + features: &[String], cli_options: &CliOptions, + tauri_dir: &Path, ) -> Result<(AppleConfig, AppleMetadata)> { let mut ios_options = cli_options.clone(); - if let Some(features) = features { - ios_options - .features - .get_or_insert(Vec::new()) - .extend_from_slice(features); - } + ios_options.features.extend_from_slice(features); let bundle_version = if let Some(bundle_version) = tauri_config .bundle @@ -232,7 +224,7 @@ pub fn get_config( } } }), - ios_features: ios_options.features.clone(), + ios_features: Some(ios_options.features.clone()), bundle_version, bundle_version_short, ios_version: Some(tauri_config.bundle.ios.minimum_system_version.clone()), @@ -241,8 +233,6 @@ pub fn get_config( let config = AppleConfig::from_raw(app.clone(), Some(raw)) .context("failed to create Apple configuration")?; - let tauri_dir = tauri_dir(); - let mut vendor_frameworks = Vec::new(); let mut frameworks = Vec::new(); for framework in tauri_config @@ -252,7 +242,7 @@ pub fn get_config( .clone() .unwrap_or_default() { - let framework_path = PathBuf::from(&framework); + let framework_path = Path::new(&framework); let ext = framework_path.extension().unwrap_or_default(); if ext.is_empty() { frameworks.push(framework); @@ -277,7 +267,7 @@ pub fn get_config( supported: true, ios: ApplePlatform { cargo_args: Some(ios_options.args), - features: ios_options.features, + features: Some(ios_options.features), frameworks: Some(frameworks), vendor_frameworks: Some(vendor_frameworks), ..Default::default() @@ -554,26 +544,14 @@ pub fn load_pbxproj(config: &AppleConfig) -> Result { pub fn synchronize_project_config( config: &AppleConfig, - tauri_config: &ConfigHandle, + tauri_config: &ConfigMetadata, pbxproj: &mut pbxproj::Pbxproj, export_options_plist: &mut plist::Dictionary, project_config: &ProjectConfig, debug: bool, ) -> Result<()> { - let identifier = tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .identifier - .clone(); - let product_name = tauri_config - .lock() - .unwrap() - .as_ref() - .unwrap() - .product_name - .clone(); + let identifier = tauri_config.identifier.clone(); + let product_name = tauri_config.product_name.clone(); let manual_signing = project_config.code_sign_identity.is_some() || project_config.provisioning_profile_uuid.is_some(); diff --git a/crates/tauri-cli/src/mobile/ios/run.rs b/crates/tauri-cli/src/mobile/ios/run.rs index 0ae1cef12..0021ef868 100644 --- a/crates/tauri-cli/src/mobile/ios/run.rs +++ b/crates/tauri-cli/src/mobile/ios/run.rs @@ -10,6 +10,7 @@ use clap::{ArgAction, Parser}; use super::{device_prompt, env}; use crate::{ error::Context, + helpers::config::{get_config as get_tauri_config, ConfigMetadata}, interface::{DevProcess, Interface, WatcherOptions}, mobile::{DevChild, TargetDevice}, ConfigValue, Result, @@ -26,7 +27,7 @@ pub struct Options { pub release: bool, /// List of cargo features to activate #[clap(short, long, action = ArgAction::Append, num_args(0..))] - pub features: Option>, + pub features: Vec, /// JSON strings or paths to JSON, JSON5 or TOML files to merge with the default configuration file /// /// Configurations are merged in the order they are provided, which means a particular value overwrites previous values when a config key-value pair conflicts. @@ -73,11 +74,13 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { } }; - let mut built_application = super::build::command( + let dirs = crate::helpers::app_paths::resolve_dirs(); + + let mut built_application = super::build::run( super::build::Options { debug: !options.release, targets: Some(vec![]), /* skips IPA build since there's no target */ - features: None, + features: Vec::new(), config: options.config.clone(), build_number: None, open: options.open, @@ -91,12 +94,19 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }), }, noise_level, + &dirs, + )?; + + let mut tauri_config = get_tauri_config( + tauri_utils::platform::Target::Ios, + &options.config.iter().map(|c| &c.0).collect::>(), + dirs.tauri, )?; // 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, @@ -114,14 +124,16 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<()> { }; if options.no_watch { - runner()?; + runner(&tauri_config)?; } else { built_application.interface.watch( + &mut tauri_config, WatcherOptions { config: options.config, additional_watch_folders: options.additional_watch_folders, }, runner, + &dirs, )?; } } diff --git a/crates/tauri-cli/src/mobile/ios/xcode_script.rs b/crates/tauri-cli/src/mobile/ios/xcode_script.rs index 34d697614..0b30ba2f4 100644 --- a/crates/tauri-cli/src/mobile/ios/xcode_script.rs +++ b/crates/tauri-cli/src/mobile/ios/xcode_script.rs @@ -5,7 +5,7 @@ use super::{ensure_init, env, get_app, get_config, read_options, MobileTarget}; use crate::{ error::{Context, ErrorExt}, - helpers::config::{get as get_tauri_config, reload as reload_tauri_config}, + helpers::config::{get_config as get_tauri_config, reload_config as reload_tauri_config}, interface::{AppInterface, Interface, Options as InterfaceOptions}, mobile::ios::LIB_OUTPUT_FILE_NAME, Error, Result, @@ -89,47 +89,43 @@ pub fn command(options: Options) -> Result<()> { .unwrap(); } - crate::helpers::app_paths::resolve(); + let dirs = crate::helpers::app_paths::resolve_dirs(); let profile = profile_from_configuration(&options.configuration); let macos = macos_from_platform(&options.platform); - let (tauri_config, cli_options) = { - let tauri_config = get_tauri_config(tauri_utils::platform::Target::Ios, &[])?; - let cli_options = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - read_options(tauri_config_) - }; - let tauri_config = if cli_options.config.is_empty() { - tauri_config - } else { + 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, )? }; - (tauri_config, cli_options) + cli_options }; let (config, metadata) = { - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - let cli_options = read_options(tauri_config_); + let cli_options = read_options(&tauri_config); let (config, metadata) = get_config( &get_app( MobileTarget::Ios, - tauri_config_, - &AppInterface::new(tauri_config_, None)?, + &tauri_config, + &AppInterface::new(&tauri_config, None, dirs.tauri)?, + dirs.tauri, ), - tauri_config_, - None, + &tauri_config, + &[], &cli_options, + dirs.tauri, )?; (config, metadata) }; @@ -142,7 +138,8 @@ pub fn command(options: Options) -> Result<()> { )?; if !cli_options.config.is_empty() { - crate::helpers::config::merge_with( + crate::helpers::config::merge_config_with( + &mut tauri_config, &cli_options .config .iter() @@ -236,10 +233,7 @@ pub fn command(options: Options) -> Result<()> { } }; - let interface = AppInterface::new( - tauri_config.lock().unwrap().as_ref().unwrap(), - Some(rust_triple.into()), - )?; + let interface = AppInterface::new(&tauri_config, Some(rust_triple.into()), dirs.tauri)?; let cflags = format!("CFLAGS_{env_triple}"); let cxxflags = format!("CFLAGS_{env_triple}"); @@ -280,11 +274,14 @@ pub fn command(options: Options) -> Result<()> { ) .context("failed to compile iOS app")?; - let out_dir = interface.app_settings().out_dir(&InterfaceOptions { - debug: matches!(profile, Profile::Debug), - target: Some(rust_triple.into()), - ..Default::default() - })?; + let out_dir = interface.app_settings().out_dir( + &InterfaceOptions { + debug: matches!(profile, Profile::Debug), + target: Some(rust_triple.into()), + ..Default::default() + }, + dirs.tauri, + )?; let lib_path = out_dir.join(format!("lib{}.a", config.app().lib_name())); if !lib_path.exists() { diff --git a/crates/tauri-cli/src/mobile/mod.rs b/crates/tauri-cli/src/mobile/mod.rs index 2a20c66b6..6b06e0cac 100644 --- a/crates/tauri-cli/src/mobile/mod.rs +++ b/crates/tauri-cli/src/mobile/mod.rs @@ -4,10 +4,7 @@ use crate::{ error::{Context, ErrorExt}, - helpers::{ - app_paths::tauri_dir, - config::{reload as reload_config, Config as TauriConfig, ConfigHandle, ConfigMetadata}, - }, + helpers::config::{reload_config, Config as TauriConfig, ConfigMetadata}, interface::{AppInterface, AppSettings, DevProcess, Interface, Options as InterfaceOptions}, ConfigValue, Error, Result, }; @@ -31,7 +28,7 @@ use std::{ fmt::{Display, Write}, fs::{read_to_string, write}, net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr}, - path::PathBuf, + path::{Path, PathBuf}, process::{exit, ExitStatus}, str::FromStr, sync::{ @@ -181,7 +178,7 @@ impl Default for DevHost { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct CliOptions { pub dev: bool, - pub features: Option>, + pub features: Vec, pub args: Vec, pub noise_level: NoiseLevel, pub vars: HashMap, @@ -193,7 +190,7 @@ impl Default for CliOptions { fn default() -> Self { Self { dev: false, - features: None, + features: Vec::new(), args: vec!["--lib".into()], noise_level: Default::default(), vars: Default::default(), @@ -217,12 +214,9 @@ fn local_ip_address(force: bool) -> &'static IpAddr { }) .collect(); - match addresses.len() { - 0 => panic!("No external IP detected."), - 1 => { - let ipaddr = addresses.first().unwrap(); - *ipaddr - } + match addresses.as_slice() { + [] => panic!("No external IP detected."), + [ipaddr] => *ipaddr, _ => { let selected = dialoguer::Select::with_theme(&dialoguer::theme::ColorfulTheme::default()) .with_prompt( @@ -252,18 +246,12 @@ struct DevUrlConfig { } fn use_network_address_for_dev_url( - config: &ConfigHandle, + config: &mut ConfigMetadata, dev_options: &mut crate::dev::Options, force_ip_prompt: bool, + tauri_dir: &Path, ) -> crate::Result { - let mut dev_url = config - .lock() - .unwrap() - .as_ref() - .unwrap() - .build - .dev_url - .clone(); + let mut dev_url = config.build.dev_url.clone(); let ip = if let Some(url) = &mut dev_url { let localhost = match url.host() { @@ -299,11 +287,13 @@ fn use_network_address_for_dev_url( }))); reload_config( + config, &dev_options .config .iter() .map(|conf| &conf.0) .collect::>(), + tauri_dir, )?; Some(ip) @@ -441,7 +431,12 @@ fn read_options(config: &ConfigMetadata) -> CliOptions { options } -pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) -> App { +pub fn get_app( + target: Target, + config: &TauriConfig, + interface: &AppInterface, + tauri_dir: &Path, +) -> App { let identifier = match target { Target::Android => config.identifier.replace('-', "_"), #[cfg(target_os = "macos")] @@ -478,22 +473,26 @@ pub fn get_app(target: Target, config: &TauriConfig, interface: &AppInterface) - }; let app_settings = interface.app_settings(); - App::from_raw(tauri_dir().to_path_buf(), raw) + let tauri_dir = tauri_dir.to_path_buf(); + App::from_raw(tauri_dir.to_path_buf(), raw) .unwrap() .with_target_dir_resolver(move |target, profile| { app_settings - .out_dir(&InterfaceOptions { - debug: matches!(profile, Profile::Debug), - target: Some(target.into()), - ..Default::default() - }) + .out_dir( + &InterfaceOptions { + debug: matches!(profile, Profile::Debug), + target: Some(target.into()), + ..Default::default() + }, + &tauri_dir, + ) .expect("failed to resolve target directory") }) } #[allow(unused_variables)] fn ensure_init( - tauri_config: &ConfigHandle, + tauri_config: &ConfigMetadata, app: &App, project_dir: PathBuf, target: Target, @@ -508,16 +507,13 @@ fn ensure_init( ) } - let tauri_config_guard = tauri_config.lock().unwrap(); - let tauri_config_ = tauri_config_guard.as_ref().unwrap(); - let mut project_outdated_reasons = Vec::new(); match target { Target::Android => { let java_folder = project_dir .join("app/src/main/java") - .join(tauri_config_.identifier.replace('.', "/").replace('-', "_")); + .join(tauri_config.identifier.replace('.', "/").replace('-', "_")); if java_folder.exists() { #[cfg(unix)] ensure_gradlew(&project_dir)?; diff --git a/crates/tauri-cli/src/remove.rs b/crates/tauri-cli/src/remove.rs index 319f60e82..ba20ae778 100644 --- a/crates/tauri-cli/src/remove.rs +++ b/crates/tauri-cli/src/remove.rs @@ -6,11 +6,7 @@ use clap::Parser; use crate::{ acl, - helpers::{ - app_paths::{resolve_frontend_dir, tauri_dir}, - cargo, - npm::PackageManager, - }, + helpers::{app_paths::resolve_frontend_dir, cargo, npm::PackageManager}, Result, }; @@ -22,11 +18,7 @@ pub struct Options { } pub fn command(options: Options) -> Result<()> { - crate::helpers::app_paths::resolve(); - run(options) -} - -pub fn run(options: Options) -> Result<()> { + let dirs = crate::helpers::app_paths::resolve_dirs(); let plugin = options.plugin; let crate_name = format!("tauri-plugin-{plugin}"); @@ -35,7 +27,6 @@ pub fn run(options: Options) -> Result<()> { let metadata = plugins.remove(plugin.as_str()).unwrap_or_default(); let frontend_dir = resolve_frontend_dir(); - let tauri_dir = tauri_dir(); let target_str = metadata .desktop_only @@ -48,14 +39,14 @@ pub fn run(options: Options) -> Result<()> { cargo::uninstall_one(cargo::CargoUninstallOptions { name: &crate_name, - cwd: Some(tauri_dir), + cwd: Some(dirs.tauri), target: target_str, })?; if !metadata.rust_only { if let Some(manager) = frontend_dir.map(PackageManager::from_project) { let npm_name = format!("@tauri-apps/plugin-{plugin}"); - manager.remove(&[npm_name], tauri_dir)?; + manager.remove(&[npm_name], dirs.tauri)?; } acl::permission::rm::command(acl::permission::rm::Options { diff --git a/crates/tauri-cli/src/signer/generate.rs b/crates/tauri-cli/src/signer/generate.rs index 97f3b3708..6ca4244c7 100644 --- a/crates/tauri-cli/src/signer/generate.rs +++ b/crates/tauri-cli/src/signer/generate.rs @@ -39,26 +39,29 @@ pub fn command(mut options: Options) -> Result<()> { save_keypair(options.force, output_path, &keypair.sk, &keypair.pk) .expect("Unable to write keypair"); - println!( - "\nYour keypair was generated successfully\nPrivate: {} (Keep it secret!)\nPublic: {}\n---------------------------", - display_path(secret_path), - display_path(public_path) - ) + println!(); + println!("Your keypair was generated successfully:"); + println!("Private: {} (Keep it secret!)", display_path(secret_path)); + println!("Public: {}", display_path(public_path)); + println!("---------------------------") } else { - println!( - "\nYour secret key was generated successfully - Keep it secret!\n{}\n\n", - keypair.sk - ); - println!( - "Your public key was generated successfully:\n{}\n\nAdd the public key in your tauri.conf.json\n---------------------------\n", - keypair.pk - ); + println!(); + println!("Your keys were generated successfully!",); + println!(); + println!("Private: (Keep it secret!)"); + println!("{}", keypair.sk); + println!(); + println!("Public:"); + println!("{}", keypair.pk); } - println!("\nEnvironment variables used to sign:"); - println!("`TAURI_SIGNING_PRIVATE_KEY` Path or String of your private key"); - println!("`TAURI_SIGNING_PRIVATE_KEY_PASSWORD` Your private key password (optional)"); - println!("\nATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not work.\n---------------------------\n"); + println!(); + println!("Environment variables used to sign:"); + println!("- `TAURI_SIGNING_PRIVATE_KEY`: String of your private key"); + println!("- `TAURI_SIGNING_PRIVATE_KEY_PATH`: Path to your private key file"); + println!("- `TAURI_SIGNING_PRIVATE_KEY_PASSWORD`: Your private key password (optional if key has no password)"); + println!(); + println!("ATTENTION: If you lose your private key OR password, you'll not be able to sign your update package and updates will not work"); Ok(()) } diff --git a/crates/tauri-cli/src/signer/sign.rs b/crates/tauri-cli/src/signer/sign.rs index 44eee5d57..a50e4e083 100644 --- a/crates/tauri-cli/src/signer/sign.rs +++ b/crates/tauri-cli/src/signer/sign.rs @@ -21,7 +21,7 @@ pub struct Options { short = 'k', long, conflicts_with("private_key_path"), - env = "TAURI_PRIVATE_KEY" + env = "TAURI_SIGNING_PRIVATE_KEY" )] private_key: Option, /// Load the private key from a file @@ -29,17 +29,50 @@ pub struct Options { short = 'f', long, conflicts_with("private_key"), - env = "TAURI_PRIVATE_KEY_PATH" + env = "TAURI_SIGNING_PRIVATE_KEY_PATH" )] private_key_path: Option, /// Set private key password when signing - #[clap(short, long, env = "TAURI_PRIVATE_KEY_PASSWORD")] + #[clap(short, long, env = "TAURI_SIGNING_PRIVATE_KEY_PASSWORD")] password: Option, /// Sign the specified file file: PathBuf, } +// Backwards compatibility with old env vars +// TODO: remove in v3.0 +fn backward_env_vars(mut options: Options) -> Options { + let get_env = |old, new| { + if let Ok(old_value) = std::env::var(old) { + println!( + "\x1b[33mWarning: The environment variable '{old}' is deprecated. Please use '{new}' instead.\x1b[0m", + ); + Some(old_value) + } else { + None + } + }; + + options.private_key = options + .private_key + .or_else(|| get_env("TAURI_PRIVATE_KEY", "TAURI_SIGNING_PRIVATE_KEY")); + + options.private_key_path = options.private_key_path.or_else(|| { + get_env("TAURI_PRIVATE_KEY_PATH", "TAURI_SIGNING_PRIVATE_KEY_PATH").map(PathBuf::from) + }); + + options.password = options.password.or_else(|| { + get_env( + "TAURI_PRIVATE_KEY_PASSWORD", + "TAURI_SIGNING_PRIVATE_KEY_PASSWORD", + ) + }); + options +} + pub fn command(mut options: Options) -> Result<()> { + options = backward_env_vars(options); + options.private_key = if let Some(private_key) = options.private_key_path { Some(std::fs::read_to_string(Path::new(&private_key)).expect("Unable to extract private key")) } else { diff --git a/crates/tauri-codegen/CHANGELOG.md b/crates/tauri-codegen/CHANGELOG.md index 197f07e11..0da7581fe 100644 --- a/crates/tauri-codegen/CHANGELOG.md +++ b/crates/tauri-codegen/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## \[2.5.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` + +## \[2.5.1] + +### Performance Improvements + +- [`8e3bd63db`](https://www.github.com/tauri-apps/tauri/commit/8e3bd63db919a4cf72bb3d28028033d8654deb34) ([#14457](https://www.github.com/tauri-apps/tauri/pull/14457) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Wrap the generated context code in a function to make rust analyzer faster + +## \[2.5.0] + +### Bug Fixes + +- [`c5008b829`](https://www.github.com/tauri-apps/tauri/commit/c5008b829dc779f0768089bff9b891fc76b11355) ([#14274](https://www.github.com/tauri-apps/tauri/pull/14274)) Do not hash empty scripts when generating the Content-Security-Policy SHA-256 hashes. +- [`7b0d4e732`](https://www.github.com/tauri-apps/tauri/commit/7b0d4e73227e42d88732b6d9fe643499dd78ec4e) ([#14265](https://www.github.com/tauri-apps/tauri/pull/14265)) Fix JavaScript SHA256 hash generation on Windows not ignoring carriage return characters. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- [`6aa7f2d85`](https://www.github.com/tauri-apps/tauri/commit/6aa7f2d852870aeba1d4dd0e07f8be2bc9b66286) Upgraded to `tauri-utils@2.8.0` + ## \[2.4.0] ### Dependencies diff --git a/crates/tauri-codegen/Cargo.toml b/crates/tauri-codegen/Cargo.toml index ea9ebd8a1..751ef1402 100644 --- a/crates/tauri-codegen/Cargo.toml +++ b/crates/tauri-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-codegen" -version = "2.4.0" +version = "2.5.2" description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -20,7 +20,7 @@ quote = "1" syn = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" -tauri-utils = { version = "2.7.0", path = "../tauri-utils", features = [ +tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [ "build", ] } thiserror = "2" @@ -30,7 +30,7 @@ brotli = { version = "8", optional = true, default-features = false, features = ] } uuid = { version = "1", features = ["v4"] } semver = "1" -ico = "0.4" +ico = "0.5" png = "0.17" json-patch = "3" url = "2" diff --git a/crates/tauri-codegen/src/context.rs b/crates/tauri-codegen/src/context.rs index ed61481d2..b60d2b9fd 100644 --- a/crates/tauri-codegen/src/context.rs +++ b/crates/tauri-codegen/src/context.rs @@ -45,12 +45,14 @@ pub struct ContextData { } fn inject_script_hashes(document: &NodeRef, key: &AssetKey, csp_hashes: &mut CspHashes) { - if let Ok(inline_script_elements) = document.select("script:not(empty)") { + if let Ok(inline_script_elements) = document.select("script:not(:empty)") { let mut scripts = Vec::new(); for inline_script_el in inline_script_elements { let script = inline_script_el.as_node().text_contents(); let mut hasher = Sha256::new(); - hasher.update(&script); + hasher.update(tauri_utils::html::normalize_script_for_csp( + script.as_bytes(), + )); let hash = hasher.finalize(); scripts.push(format!( "'sha256-{}'", @@ -467,19 +469,24 @@ pub fn context_codegen(data: ContextData) -> EmbeddedAssetsResult { }); Ok(quote!({ - let thread = ::std::thread::Builder::new() - .name(String::from("generated tauri context creation")) - .stack_size(8 * 1024 * 1024) - .spawn(|| #context) - .expect("unable to create thread with 8MiB stack"); + // Wrapping in a function to make rust analyzer faster, + // see https://github.com/tauri-apps/tauri/pull/14457 + fn inner() -> #root::Context { + let thread = ::std::thread::Builder::new() + .name(String::from("generated tauri context creation")) + .stack_size(8 * 1024 * 1024) + .spawn(|| #context) + .expect("unable to create thread with 8MiB stack"); - match thread.join() { - Ok(context) => context, - Err(_) => { - eprintln!("the generated Tauri `Context` panicked during creation"); - ::std::process::exit(101); + match thread.join() { + Ok(context) => context, + Err(_) => { + eprintln!("the generated Tauri `Context` panicked during creation"); + ::std::process::exit(101); + } } } + inner() })) } diff --git a/crates/tauri-codegen/src/embedded_assets.rs b/crates/tauri-codegen/src/embedded_assets.rs index 20b00a105..ede7ee6d9 100644 --- a/crates/tauri-codegen/src/embedded_assets.rs +++ b/crates/tauri-codegen/src/embedded_assets.rs @@ -180,10 +180,12 @@ impl CspHashes { if dangerous_disable_asset_csp_modification.can_modify("script-src") { let mut hasher = Sha256::new(); hasher.update( - &std::fs::read(path).map_err(|error| EmbeddedAssetsError::AssetRead { - path: path.to_path_buf(), - error, - })?, + &std::fs::read(path) + .map(|b| tauri_utils::html::normalize_script_for_csp(&b)) + .map_err(|error| EmbeddedAssetsError::AssetRead { + path: path.to_path_buf(), + error, + })?, ); let hash = hasher.finalize(); self.scripts.push(format!( diff --git a/crates/tauri-driver/Cargo.toml b/crates/tauri-driver/Cargo.toml index ad44b8a89..9b35fe111 100644 --- a/crates/tauri-driver/Cargo.toml +++ b/crates/tauri-driver/Cargo.toml @@ -31,8 +31,8 @@ tokio = { version = "1", features = ["macros"] } which = "8" [target."cfg(unix)".dependencies] -signal-hook = "0.3" -signal-hook-tokio = { version = "0.3", features = ["futures-v0_3"] } +signal-hook = "0.4" +signal-hook-tokio = { version = "0.4", features = ["futures-v0_3"] } [target."cfg(windows)".dependencies] win32job = "2" diff --git a/crates/tauri-macos-sign/CHANGELOG.md b/crates/tauri-macos-sign/CHANGELOG.md index 93329f55d..6cccf2a3e 100644 --- a/crates/tauri-macos-sign/CHANGELOG.md +++ b/crates/tauri-macos-sign/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## \[2.3.2] + +### Dependencies + +- [`514cf21e1`](https://www.github.com/tauri-apps/tauri/commit/514cf21e1417c7a78a0db494f891ba79d948b73d) ([#14591](https://www.github.com/tauri-apps/tauri/pull/14591) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) Update num-bigint-dig from 0.8.4 to 0.8.6 + +## \[2.3.1] + +### Performance Improvements + +- [`ee3cc4a91`](https://www.github.com/tauri-apps/tauri/commit/ee3cc4a91bf1315ecaefe90f423ffd55ef6c40db) ([#14475](https://www.github.com/tauri-apps/tauri/pull/14475) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) perf: remove needless clones in various files for improved performance. No user facing changes. + +## \[2.3.0] + +### Enhancements + +- [`f59bf9d53`](https://www.github.com/tauri-apps/tauri/commit/f59bf9d5392ffd209e26ce5259c26d1acc31c4ba) ([#14337](https://www.github.com/tauri-apps/tauri/pull/14337) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) **Potentially breaking change:** Export custom Error enum instead of using anyhow. The changes happened in https://github.com/tauri-apps/tauri/pull/14126. + ## \[2.2.0] ### New Features diff --git a/crates/tauri-macos-sign/Cargo.toml b/crates/tauri-macos-sign/Cargo.toml index 37e787cd4..309938c27 100644 --- a/crates/tauri-macos-sign/Cargo.toml +++ b/crates/tauri-macos-sign/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-macos-sign" -version = "2.2.0" +version = "2.3.2" authors = ["Tauri Programme within The Commons Conservancy"] license = "Apache-2.0 OR MIT" keywords = ["codesign", "signing", "macos", "ios", "tauri"] @@ -15,7 +15,8 @@ serde = { version = "1", features = ["derive"] } serde_json = "1" tempfile = "3" x509-certificate = "0.23" -once-cell-regex = "0.2" +once_cell = "1" +regex = "1" os_pipe = "1" plist = "1" rand = "0.9" diff --git a/crates/tauri-macos-sign/src/keychain/identity.rs b/crates/tauri-macos-sign/src/keychain/identity.rs index a39c48423..6ac146915 100644 --- a/crates/tauri-macos-sign/src/keychain/identity.rs +++ b/crates/tauri-macos-sign/src/keychain/identity.rs @@ -2,7 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -use once_cell_regex::regex; +use once_cell::sync::OnceCell; +use regex::Regex; use std::{collections::BTreeSet, path::Path, process::Command}; use x509_certificate::certificate::X509Certificate; @@ -49,9 +50,10 @@ impl Team { organization } else { println!( - "found cert {common_name:?} but failed to get organization; falling back to displaying common name" - ); - regex!(r"Apple Develop\w+: (.*) \(.+\)") + "found cert {common_name:?} but failed to get organization; falling back to displaying common name" + ); + static APPLE_DEV: OnceCell = OnceCell::new(); + APPLE_DEV.get_or_init(|| Regex::new(r"Apple Develop\w+: (.*) \(.+\)").unwrap()) .captures(&common_name) .map(|caps| caps[1].to_owned()) .unwrap_or_else(|| { diff --git a/crates/tauri-macos-sign/src/lib.rs b/crates/tauri-macos-sign/src/lib.rs index 64a9c3d57..87e30fdee 100644 --- a/crates/tauri-macos-sign/src/lib.rs +++ b/crates/tauri-macos-sign/src/lib.rs @@ -238,7 +238,7 @@ fn notarize_inner( String::from_utf8_lossy(&output.stdout) ))) } else { - Err(Error::Notarize(log_message.to_string())) + Err(Error::Notarize(log_message)) } } else { Err(Error::ParseNotarytoolOutput { diff --git a/crates/tauri-macros/CHANGELOG.md b/crates/tauri-macros/CHANGELOG.md index 875c2c797..61d35b3bc 100644 --- a/crates/tauri-macros/CHANGELOG.md +++ b/crates/tauri-macros/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## \[2.5.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` +- Upgraded to `tauri-codegen@2.5.2` + +## \[2.5.1] + +### Bug Fixes + +- [`4b00130b8`](https://www.github.com/tauri-apps/tauri/commit/4b00130b86a27b6f121bf57897b5e92d83bcc0fc) ([#14385](https://www.github.com/tauri-apps/tauri/pull/14385) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix iOS deadlock when running on the simulator from Xcode by properly piping stdout/stderr messages through the Xcode console and OSLog. + +### Dependencies + +- Upgraded to `tauri-codegen@2.5.1` + +## \[2.5.0] + +### Bug Fixes + +- [`69476d8e2`](https://www.github.com/tauri-apps/tauri/commit/69476d8e2314b85bf46046140bc5495fe29b7d29) ([#14170](https://www.github.com/tauri-apps/tauri/pull/14170)) Fix the stack overflow when having too many commands in a single invoke handler in release build + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- Upgraded to `tauri-codegen@2.5.0` +- [`6aa7f2d85`](https://www.github.com/tauri-apps/tauri/commit/6aa7f2d852870aeba1d4dd0e07f8be2bc9b66286) Upgraded to `tauri-utils@2.8.0` + ## \[2.4.0] ### Dependencies diff --git a/crates/tauri-macros/Cargo.toml b/crates/tauri-macros/Cargo.toml index 82cf3d976..7a096d01c 100644 --- a/crates/tauri-macros/Cargo.toml +++ b/crates/tauri-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-macros" -version = "2.4.0" +version = "2.5.2" description = "Macros for the tauri crate." exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -20,8 +20,8 @@ proc-macro2 = { version = "1", features = ["span-locations"] } quote = "1" syn = { version = "2", features = ["full"] } heck = "0.5" -tauri-codegen = { version = "2.4.0", default-features = false, path = "../tauri-codegen" } -tauri-utils = { version = "2.7.0", path = "../tauri-utils" } +tauri-codegen = { version = "2.5.2", default-features = false, path = "../tauri-codegen" } +tauri-utils = { version = "2.8.1", path = "../tauri-utils" } [features] custom-protocol = [] diff --git a/crates/tauri-plugin/CHANGELOG.md b/crates/tauri-plugin/CHANGELOG.md index c6c10bebd..51505ca06 100644 --- a/crates/tauri-plugin/CHANGELOG.md +++ b/crates/tauri-plugin/CHANGELOG.md @@ -1,5 +1,24 @@ # Changelog +## \[2.5.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` + +## \[2.5.1] + +### Bug Fixes + +- [`4b6b8690a`](https://www.github.com/tauri-apps/tauri/commit/4b6b8690ab886ebdf1307951cffbe03e31280baa) ([#14347](https://www.github.com/tauri-apps/tauri/pull/14347) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + +## \[2.5.0] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- [`6aa7f2d85`](https://www.github.com/tauri-apps/tauri/commit/6aa7f2d852870aeba1d4dd0e07f8be2bc9b66286) Upgraded to `tauri-utils@2.8.0` + ## \[2.4.0] ### New Features diff --git a/crates/tauri-plugin/Cargo.toml b/crates/tauri-plugin/Cargo.toml index 7b2a6ae95..c774a8862 100644 --- a/crates/tauri-plugin/Cargo.toml +++ b/crates/tauri-plugin/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-plugin" -version = "2.4.0" +version = "2.5.2" description = "Build script and runtime Tauri plugin definitions" authors.workspace = true homepage.workspace = true @@ -12,8 +12,6 @@ rust-version.workspace = true [package.metadata.docs.rs] features = ["build", "runtime"] -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] [features] build = [ @@ -30,7 +28,7 @@ runtime = [] [dependencies] anyhow = { version = "1", optional = true } serde = { version = "1", optional = true } -tauri-utils = { version = "2.7.0", default-features = false, features = [ +tauri-utils = { version = "2.8.1", default-features = false, features = [ "build", ], path = "../tauri-utils" } serde_json = { version = "1", optional = true } diff --git a/crates/tauri-runtime-wry/CHANGELOG.md b/crates/tauri-runtime-wry/CHANGELOG.md index c53d32e43..76f0a046f 100644 --- a/crates/tauri-runtime-wry/CHANGELOG.md +++ b/crates/tauri-runtime-wry/CHANGELOG.md @@ -1,5 +1,45 @@ # Changelog +## \[2.9.3] + +### Bug Fixes + +- [`251203b89`](https://www.github.com/tauri-apps/tauri/commit/251203b8963419cb3b40741767393e8f3c909ef9) ([#14637](https://www.github.com/tauri-apps/tauri/pull/14637) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix `Monitor::work_area` returns logical position and size inside the `PhysicalRect` on Linux + +## \[2.9.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` +- Upgraded to `tauri-runtime@2.9.2` + +## \[2.9.1] + +### Bug Fixes + +- [`4b6b8690a`](https://www.github.com/tauri-apps/tauri/commit/4b6b8690ab886ebdf1307951cffbe03e31280baa) ([#14347](https://www.github.com/tauri-apps/tauri/pull/14347) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-runtime@2.9.1` + +## \[2.9.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scroll_bar_style` option to the Webview and WebviewWindow builders. + The possible values for this option are gated behind conditional compilation + flags, and will need to be applied using conditional compilation if customised. + +### Bug Fixes + +- [`684791efa`](https://www.github.com/tauri-apps/tauri/commit/684791efa6f3c671a0435d456ac208bca871d8c1) ([#14276](https://www.github.com/tauri-apps/tauri/pull/14276)) Always try to create macOS WebKit webview, even if webkit runtime doesn't get detected correctly + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- Upgraded to `tauri-runtime@2.9.0` + ## \[2.8.1] ### Bug Fixes diff --git a/crates/tauri-runtime-wry/Cargo.toml b/crates/tauri-runtime-wry/Cargo.toml index d2d7a34ff..3abe48253 100644 --- a/crates/tauri-runtime-wry/Cargo.toml +++ b/crates/tauri-runtime-wry/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-runtime-wry" -version = "2.8.1" +version = "2.9.3" description = "Wry bindings to the Tauri runtime" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -12,20 +12,16 @@ license.workspace = true edition.workspace = true rust-version.workspace = true -[package.metadata.docs.rs] -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] - [dependencies] -wry = { version = "0.53.2", default-features = false, features = [ +wry = { version = "0.54.0", default-features = false, features = [ "drag-drop", "protocol", "os-webview", "linux-body", ] } -tao = { version = "0.34.2", default-features = false, features = ["rwh_06"] } -tauri-runtime = { version = "2.8.0", path = "../tauri-runtime" } -tauri-utils = { version = "2.7.0", path = "../tauri-utils" } +tao = { version = "0.34.5", default-features = false, features = ["rwh_06"] } +tauri-runtime = { version = "2.9.2", path = "../tauri-runtime" } +tauri-utils = { version = "2.8.1", path = "../tauri-utils" } raw-window-handle = "0.6" http = "1" url = "2" diff --git a/crates/tauri-runtime-wry/src/lib.rs b/crates/tauri-runtime-wry/src/lib.rs index 4b47b9d17..61799d039 100644 --- a/crates/tauri-runtime-wry/src/lib.rs +++ b/crates/tauri-runtime-wry/src/lib.rs @@ -37,7 +37,13 @@ use tauri_runtime::{ use objc2::rc::Retained; #[cfg(target_os = "macos")] use tao::platform::macos::{EventLoopWindowTargetExtMacOS, WindowBuilderExtMacOS}; -#[cfg(target_os = "linux")] +#[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" +))] use tao::platform::unix::{WindowBuilderExtUnix, WindowExtUnix}; #[cfg(windows)] use tao::platform::windows::{WindowBuilderExtWindows, WindowExtWindows}; @@ -812,7 +818,7 @@ impl WindowBuilder for WindowBuilderWrapper { { // TODO: find a proper way to prevent webview being pushed out of the window. // Workround for issue: https://github.com/tauri-apps/tauri/issues/10225 - // The window requies `NSFullSizeContentViewWindowMask` flag to prevent devtools + // The window requires `NSFullSizeContentViewWindowMask` flag to prevent devtools // pushing the content view out of the window. // By setting the default style to `TitleBarStyle::Visible` should fix the issue for most of the users. builder = builder.title_bar_style(TitleBarStyle::Visible); @@ -862,7 +868,13 @@ impl WindowBuilder for WindowBuilderWrapper { "); } - #[cfg(target_os = "linux")] + #[cfg(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] { // Mouse event is disabled on Linux since sudden event bursts could block event loop. window.inner = window.inner.with_cursor_moved_event(false); @@ -1194,7 +1206,14 @@ impl WindowBuilder for WindowBuilderWrapper { self } - #[cfg(any(windows, target_os = "linux"))] + #[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] fn skip_taskbar(mut self, skip: bool) -> Self { self.inner = self.inner.with_skip_taskbar(skip); self @@ -2422,6 +2441,18 @@ impl Drop for WebviewWrapper { if let Some(web_context) = context_store.get_mut(&self.context_key) { web_context.referenced_by_webviews.remove(&self.label); + // https://github.com/tauri-apps/tauri/issues/14626 + // Because WebKit does not close its network process even when no webviews are running, + // we need to ensure to re-use the existing process on Linux by keeping the WebContext + // alive for the lifetime of the app. + // WebKit on macOS handles this itself. + #[cfg(not(any( + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + )))] if web_context.referenced_by_webviews.is_empty() { context_store.remove(&self.context_key); } @@ -3405,7 +3436,14 @@ fn handle_user_message( } #[allow(unused_variables)] WindowMessage::SetSkipTaskbar(skip) => { - #[cfg(any(windows, target_os = "linux"))] + #[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] let _ = window.set_skip_taskbar(skip); } WindowMessage::SetCursorGrab(grab) => { @@ -4535,7 +4573,11 @@ You may have it installed on another user account, but it is not available for t "#, ); - return Err(Error::WebviewRuntimeNotInstalled); + if cfg!(target_os = "macos") { + log::warn!("WebKit webview runtime not found, attempting to create webview anyway."); + } else { + return Err(Error::WebviewRuntimeNotInstalled); + } } #[allow(unused_mut)] diff --git a/crates/tauri-runtime-wry/src/monitor/linux.rs b/crates/tauri-runtime-wry/src/monitor/linux.rs index 6b6a33bce..62f87eb05 100644 --- a/crates/tauri-runtime-wry/src/monitor/linux.rs +++ b/crates/tauri-runtime-wry/src/monitor/linux.rs @@ -4,14 +4,15 @@ use gtk::prelude::MonitorExt; use tao::platform::unix::MonitorHandleExtUnix; -use tauri_runtime::dpi::{PhysicalPosition, PhysicalRect, PhysicalSize}; +use tauri_runtime::dpi::{LogicalPosition, LogicalSize, PhysicalRect}; impl super::MonitorExt for tao::monitor::MonitorHandle { fn work_area(&self) -> PhysicalRect { let rect = self.gdk_monitor().workarea(); + let scale_factor = self.scale_factor(); PhysicalRect { - size: PhysicalSize::new(rect.width() as u32, rect.height() as u32), - position: PhysicalPosition::new(rect.x(), rect.y()), + size: LogicalSize::new(rect.width() as u32, rect.height() as u32).to_physical(scale_factor), + position: LogicalPosition::new(rect.x(), rect.y()).to_physical(scale_factor), } } } diff --git a/crates/tauri-runtime-wry/src/window/mod.rs b/crates/tauri-runtime-wry/src/window/mod.rs index 02af23661..b18543e5d 100644 --- a/crates/tauri-runtime-wry/src/window/mod.rs +++ b/crates/tauri-runtime-wry/src/window/mod.rs @@ -39,7 +39,7 @@ pub trait WindowExt { /// - **Android / iOS**: Unsupported. fn center(&self) {} - /// Clears the window sufrace. i.e make it it transparent. + /// Clears the window surface. i.e make it transparent. #[cfg(windows)] fn draw_surface( &self, diff --git a/crates/tauri-runtime/CHANGELOG.md b/crates/tauri-runtime/CHANGELOG.md index 128b2ab7d..c4ae73bec 100644 --- a/crates/tauri-runtime/CHANGELOG.md +++ b/crates/tauri-runtime/CHANGELOG.md @@ -1,5 +1,29 @@ # Changelog +## \[2.9.2] + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` + +## \[2.9.1] + +### Bug Fixes + +- [`4b6b8690a`](https://www.github.com/tauri-apps/tauri/commit/4b6b8690ab886ebdf1307951cffbe03e31280baa) ([#14347](https://www.github.com/tauri-apps/tauri/pull/14347) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + +## \[2.9.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scroll_bar_style` option to the Webview and WebviewWindow builders. + The possible values for this option are gated behind conditional compilation + flags, and will need to be applied using conditional compilation if customised. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` + ## \[2.8.0] ### New Features diff --git a/crates/tauri-runtime/Cargo.toml b/crates/tauri-runtime/Cargo.toml index a1ab86ade..53db45873 100644 --- a/crates/tauri-runtime/Cargo.toml +++ b/crates/tauri-runtime/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-runtime" -version = "2.8.0" +version = "2.9.2" description = "Runtime for Tauri applications" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -14,8 +14,6 @@ rust-version.workspace = true [package.metadata.docs.rs] all-features = true -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] default-target = "x86_64-unknown-linux-gnu" targets = [ "x86_64-pc-windows-msvc", @@ -29,7 +27,7 @@ targets = [ serde = { version = "1", features = ["derive"] } serde_json = "1" thiserror = "2" -tauri-utils = { version = "2.7.0", path = "../tauri-utils" } +tauri-utils = { version = "2.8.1", path = "../tauri-utils" } http = "1" raw-window-handle = "0.6" url = { version = "2" } diff --git a/crates/tauri-runtime/src/lib.rs b/crates/tauri-runtime/src/lib.rs index a8d17181e..5bf869dcd 100644 --- a/crates/tauri-runtime/src/lib.rs +++ b/crates/tauri-runtime/src/lib.rs @@ -90,23 +90,18 @@ pub enum UserAttentionType { Informational, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] +#[derive(Default, Debug, Clone, Copy, PartialEq, Eq, Deserialize)] #[serde(tag = "type")] pub enum DeviceEventFilter { /// Always filter out device events. Always, /// Filter out device events while the window is not focused. + #[default] Unfocused, /// Report all device events regardless of window focus. Never, } -impl Default for DeviceEventFilter { - fn default() -> Self { - Self::Unfocused - } -} - /// Defines the orientation that a window resize will be performed. #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize)] pub enum ResizeDirection { @@ -404,8 +399,25 @@ pub trait Runtime: Debug + Sized + 'static { fn new(args: RuntimeInitArgs) -> Result; /// Creates a new webview runtime on any thread. - #[cfg(any(windows, target_os = "linux"))] - #[cfg_attr(docsrs, doc(cfg(any(windows, target_os = "linux"))))] + #[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] + #[cfg_attr( + docsrs, + doc(cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))) + )] fn new_any_thread(args: RuntimeInitArgs) -> Result; /// Creates an `EventLoopProxy` that can be used to dispatch user events to the main event loop. diff --git a/crates/tauri-runtime/src/webview.rs b/crates/tauri-runtime/src/webview.rs index f9c904ef9..80f7edf0e 100644 --- a/crates/tauri-runtime/src/webview.rs +++ b/crates/tauri-runtime/src/webview.rs @@ -23,7 +23,7 @@ use std::{ sync::Arc, }; -type UriSchemeProtocol = dyn Fn(&str, http::Request>, Box>) + Send>) +type UriSchemeProtocolHandler = dyn Fn(&str, http::Request>, Box>) + Send>) + Send + Sync + 'static; @@ -199,7 +199,8 @@ pub struct PendingWebview> { /// The [`WebviewAttributes`] that the webview will be created with. pub webview_attributes: WebviewAttributes, - pub uri_scheme_protocols: HashMap>, + /// Custom protocols to register on the webview + pub uri_scheme_protocols: HashMap>, /// How to handle IPC calls on the webview. pub ipc_handler: Option>, @@ -263,12 +264,12 @@ impl> PendingWebview { >( &mut self, uri_scheme: N, - protocol: H, + protocol_handler: H, ) { let uri_scheme = uri_scheme.into(); self .uri_scheme_protocols - .insert(uri_scheme, Box::new(protocol)); + .insert(uri_scheme, Box::new(protocol_handler)); } #[cfg(target_os = "android")] @@ -362,7 +363,7 @@ pub struct WebviewAttributes { /// see https://docs.rs/objc2-web-kit/latest/objc2_web_kit/struct.WKWebView.html#method.allowsLinkPreview pub allow_link_preview: bool, pub scroll_bar_style: ScrollBarStyle, - /// Allows overriding the the keyboard accessory view on iOS. + /// Allows overriding the keyboard accessory view on iOS. /// Returning `None` effectively removes the view. /// /// The closure parameter is the webview instance. diff --git a/crates/tauri-runtime/src/window.rs b/crates/tauri-runtime/src/window.rs index cdda26883..652832c1e 100644 --- a/crates/tauri-runtime/src/window.rs +++ b/crates/tauri-runtime/src/window.rs @@ -247,19 +247,19 @@ pub trait WindowBuilder: WindowBuilderBase { #[must_use] fn center(self) -> Self; - /// The initial position of the window's. + /// The initial position of the window in logical pixels. #[must_use] fn position(self, x: f64, y: f64) -> Self; - /// Window size. + /// Window size in logical pixels. #[must_use] fn inner_size(self, width: f64, height: f64) -> Self; - /// Window min inner size. + /// Window min inner size in logical pixels. #[must_use] fn min_inner_size(self, min_width: f64, min_height: f64) -> Self; - /// Window max inner size. + /// Window max inner size in logical pixels. #[must_use] fn max_inner_size(self, max_width: f64, max_height: f64) -> Self; diff --git a/crates/tauri-schema-generator/schemas/config.schema.json b/crates/tauri-schema-generator/schemas/config.schema.json index 6f8593965..ffc72c24e 100644 --- a/crates/tauri-schema-generator/schemas/config.schema.json +++ b/crates/tauri-schema-generator/schemas/config.schema.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "https://schema.tauri.app/config/2.8.5", + "$id": "https://schema.tauri.app/config/2.9.5", "title": "Config", "description": "The Tauri configuration object.\n It is read from a file where you can define your frontend assets,\n configure the bundler and define a tray icon.\n\n The configuration file is generated by the\n [`tauri init`](https://v2.tauri.app/reference/cli/#init) command that lives in\n your Tauri application source directory (src-tauri).\n\n Once generated, you may modify it at will to customize your Tauri application.\n\n ## File Formats\n\n By default, the configuration is defined as a JSON file named `tauri.conf.json`.\n\n Tauri also supports JSON5 and TOML files via the `config-json5` and `config-toml` Cargo features, respectively.\n The JSON5 file name must be either `tauri.conf.json` or `tauri.conf.json5`.\n The TOML file name is `Tauri.toml`.\n\n ## Platform-Specific Configuration\n\n In addition to the default configuration file, Tauri can\n read a platform-specific configuration from `tauri.linux.conf.json`,\n `tauri.windows.conf.json`, `tauri.macos.conf.json`, `tauri.android.conf.json` and `tauri.ios.conf.json`\n (or `Tauri.linux.toml`, `Tauri.windows.toml`, `Tauri.macos.toml`, `Tauri.android.toml` and `Tauri.ios.toml` if the `Tauri.toml` format is used),\n which gets merged with the main configuration object.\n\n ## Configuration Structure\n\n The configuration is composed of the following objects:\n\n - [`app`](#appconfig): The Tauri configuration\n - [`build`](#buildconfig): The build configuration\n - [`bundle`](#bundleconfig): The bundle configurations\n - [`plugins`](#pluginconfig): The plugins configuration\n\n Example tauri.config.json file:\n\n ```json\n {\n \"productName\": \"tauri-app\",\n \"version\": \"0.1.0\",\n \"build\": {\n \"beforeBuildCommand\": \"\",\n \"beforeDevCommand\": \"\",\n \"devUrl\": \"http://localhost:3000\",\n \"frontendDist\": \"../dist\"\n },\n \"app\": {\n \"security\": {\n \"csp\": null\n },\n \"windows\": [\n {\n \"fullscreen\": false,\n \"height\": 600,\n \"resizable\": true,\n \"title\": \"Tauri App\",\n \"width\": 800\n }\n ]\n },\n \"bundle\": {},\n \"plugins\": {}\n }\n ```", "type": "object", @@ -84,6 +84,7 @@ "default": { "active": false, "android": { + "autoIncrementVersionCode": false, "minSdkVersion": 24 }, "createUpdaterArtifacts": false, @@ -167,7 +168,7 @@ "type": "object", "properties": { "windows": { - "description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", + "description": "The app windows configuration.\n\n ## Example:\n\n To create a window at app startup\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n If not specified, the window's label (its identifier) defaults to \"main\",\n you can use this label to get the window through\n `app.get_webview_window` in Rust or `WebviewWindow.getByLabel` in JavaScript\n\n When working with multiple windows, each window will need an unique label\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"label\": \"main\", \"width\": 800, \"height\": 600 },\n { \"label\": \"secondary\", \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n You can also set `create` to false and use this config through the Rust APIs\n\n ```json\n {\n \"app\": {\n \"windows\": [\n { \"create\": false, \"width\": 800, \"height\": 600 }\n ]\n }\n }\n ```\n\n and use it like this\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", "default": [], "type": "array", "items": { @@ -233,7 +234,7 @@ "type": "string" }, "create": { - "description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).\n\n ## Example:\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", + "description": "Whether Tauri should create this window at app startup or not.\n\n When this is set to `false` you must manually grab the config object via `app.config().app.windows`\n and create it with [`WebviewWindowBuilder::from_config`](https://docs.rs/tauri/2/tauri/webview/struct.WebviewWindowBuilder.html#method.from_config).\n\n ## Example:\n\n ```rust\n tauri::Builder::default()\n .setup(|app| {\n tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?;\n Ok(())\n });\n ```", "default": true, "type": "boolean" }, @@ -264,7 +265,7 @@ "type": "boolean" }, "x": { - "description": "The horizontal position of the window's top left corner", + "description": "The horizontal position of the window's top left corner in logical pixels", "type": [ "number", "null" @@ -272,7 +273,7 @@ "format": "double" }, "y": { - "description": "The vertical position of the window's top left corner", + "description": "The vertical position of the window's top left corner in logical pixels", "type": [ "number", "null" @@ -280,19 +281,19 @@ "format": "double" }, "width": { - "description": "The window width.", + "description": "The window width in logical pixels.", "default": 800.0, "type": "number", "format": "double" }, "height": { - "description": "The window height.", + "description": "The window height in logical pixels.", "default": 600.0, "type": "number", "format": "double" }, "minWidth": { - "description": "The min window width.", + "description": "The min window width in logical pixels.", "type": [ "number", "null" @@ -300,7 +301,7 @@ "format": "double" }, "minHeight": { - "description": "The min window height.", + "description": "The min window height in logical pixels.", "type": [ "number", "null" @@ -308,7 +309,7 @@ "format": "double" }, "maxWidth": { - "description": "The max window width.", + "description": "The max window width in logical pixels.", "type": [ "number", "null" @@ -316,7 +317,7 @@ "format": "double" }, "maxHeight": { - "description": "The max window height.", + "description": "The max window height in logical pixels.", "type": [ "number", "null" @@ -654,13 +655,13 @@ ], "properties": { "width": { - "description": "Horizontal margin in physical unit", + "description": "Horizontal margin in physical pixels", "type": "integer", "format": "uint32", "minimum": 0.0 }, "height": { - "description": "Vertical margin in physical unit", + "description": "Vertical margin in physical pixels", "type": "integer", "format": "uint32", "minimum": 0.0 @@ -923,7 +924,7 @@ ] }, { - "description": "Mica effect that matches the system dark perefence **Windows 11 Only**", + "description": "Mica effect that matches the system dark preference **Windows 11 Only**", "type": "string", "enum": [ "mica" @@ -944,7 +945,7 @@ ] }, { - "description": "Tabbed effect that matches the system dark perefence **Windows 11 Only**", + "description": "Tabbed effect that matches the system dark preference **Windows 11 Only**", "type": "string", "enum": [ "tabbed" @@ -1298,7 +1299,7 @@ "additionalProperties": false }, "FsScope": { - "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`,\n `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", + "description": "Protocol scope definition.\n It is a list of glob patterns that restrict the API access from the webview.\n\n Each pattern can start with a variable that resolves to a system base directory.\n The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,\n `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,\n `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$TEMP`,\n `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.", "anyOf": [ { "description": "A list of paths that are allowed by this scope.", @@ -1993,7 +1994,7 @@ "description": "Defines the URL or assets to embed in the application.", "anyOf": [ { - "description": "An external URL that should be used as the default application URL.", + "description": "An external URL that should be used as the default application URL. No assets are embedded in the app in this case.", "type": "string", "format": "uri" }, @@ -2002,7 +2003,7 @@ "type": "string" }, { - "description": "An array of files to embed on the app.", + "description": "An array of files to embed in the app.", "type": "array", "items": { "type": "string" @@ -2288,6 +2289,7 @@ "android": { "description": "Android configuration.", "default": { + "autoIncrementVersionCode": false, "minSdkVersion": 24 }, "allOf": [ @@ -2796,7 +2798,7 @@ "type": "object", "properties": { "version": { - "description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and foruth fields have a maximum value of 65,535.\n\n See for more info.", + "description": "MSI installer version in the format `major.minor.patch.build` (build is optional).\n\n Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set.\n\n The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255.\n The third and fourth fields have a maximum value of 65,535.\n\n See for more info.", "type": [ "string", "null" @@ -3100,7 +3102,7 @@ "description": "Custom Signing Command configuration.", "anyOf": [ { - "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`].", + "description": "A string notation of the script to execute.\n\n \"%1\" will be replaced with the path to the binary to be signed.\n\n This is a simpler notation for the command.\n Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments.\n\n If you need to use whitespace in the command or arguments, use the object notation [`Self::CommandWithOptions`].", "type": "string" }, { @@ -3853,6 +3855,11 @@ "format": "uint32", "maximum": 2100000000.0, "minimum": 1.0 + }, + "autoIncrementVersionCode": { + "description": "Whether to automatically increment the `versionCode` on each build.\n\n - If `true`, the generator will try to read the last `versionCode` from\n `tauri.properties` and increment it by 1 for every build.\n - If `false` or not set, it falls back to `version_code` or semver-derived logic.\n\n Note that to use this feature, you should remove `/tauri.properties` from `src-tauri/gen/android/app/.gitignore` so the current versionCode is committed to the repository.", + "default": false, + "type": "boolean" } }, "additionalProperties": false diff --git a/crates/tauri-schema-worker/Cargo.toml b/crates/tauri-schema-worker/Cargo.toml index 70462e5f9..34da45cc7 100644 --- a/crates/tauri-schema-worker/Cargo.toml +++ b/crates/tauri-schema-worker/Cargo.toml @@ -8,8 +8,8 @@ publish = false crate-type = ["cdylib"] [dependencies] -worker = { version = "0.6", features = ['http', 'axum'] } -worker-macros = { version = "0.6", features = ['http'] } +worker = { version = "0.7", features = ['http', 'axum'] } +worker-macros = { version = "0.7", features = ['http'] } console_error_panic_hook = { version = "0.1" } axum = { version = "0.8", default-features = false } tower-service = "0.3" 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-schema-worker/wrangler.toml b/crates/tauri-schema-worker/wrangler.toml index c7b811908..661b6059a 100644 --- a/crates/tauri-schema-worker/wrangler.toml +++ b/crates/tauri-schema-worker/wrangler.toml @@ -7,8 +7,9 @@ main = "build/worker/shim.mjs" compatibility_date = "2023-08-23" send_metrics = false +# The minor version of worker-build must match worker/worker-macros in Cargo.toml! [build] -command = "cargo install -q worker-build && worker-build --release" +command = "cargo install -q worker-build@^0.7 && worker-build --release" [observability] enabled = true diff --git a/crates/tauri-utils/CHANGELOG.md b/crates/tauri-utils/CHANGELOG.md index 73e37c472..a63e5103b 100644 --- a/crates/tauri-utils/CHANGELOG.md +++ b/crates/tauri-utils/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## \[2.8.1] + +### Bug Fixes + +- [`1573c7240`](https://www.github.com/tauri-apps/tauri/commit/1573c72402352949d1fd3ca5c6fdbee46fe69fbb) ([#14561](https://www.github.com/tauri-apps/tauri/pull/14561) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused schema files to have `\r` characters on Windows. + +## \[2.8.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scrollBarStyle` option to the window configuration. +- [`3b4fac201`](https://www.github.com/tauri-apps/tauri/commit/3b4fac2017832d426dd07c5e24e26684eda57f7b) ([#14194](https://www.github.com/tauri-apps/tauri/pull/14194)) Add `tauri.conf.json > bundle > android > autoIncrementVersionCode` config option to automatically increment the Android version code. +- [`3d6868d09`](https://www.github.com/tauri-apps/tauri/commit/3d6868d09c323d68a152f3c3f8c7256311bd020a) ([#14128](https://www.github.com/tauri-apps/tauri/pull/14128)) Added `FileAssociation::exported_type` and `FileAssociation::content_types` for better support to defining custom types on macOS. +- [`ed7c9a410`](https://www.github.com/tauri-apps/tauri/commit/ed7c9a4100e08c002212265549d12130d021ad1e) ([#14108](https://www.github.com/tauri-apps/tauri/pull/14108)) Added `bundle > macOS > infoPlist` and `bundle > iOS > infoPlist` configurations to allow defining custom Info.plist extensions. +- [`7b0d4e732`](https://www.github.com/tauri-apps/tauri/commit/7b0d4e73227e42d88732b6d9fe643499dd78ec4e) ([#14265](https://www.github.com/tauri-apps/tauri/pull/14265)) Added `html::normalize_script_for_csp`. +- [`cc8c0b531`](https://www.github.com/tauri-apps/tauri/commit/cc8c0b53171173dbd1d01781a50de1a3ea159031) ([#14031](https://www.github.com/tauri-apps/tauri/pull/14031)) Added support to universal app links on macOS with the `plugins > deep-link > desktop > domains` configuration. + +### Enhancements + +- [`59089723f`](https://www.github.com/tauri-apps/tauri/commit/59089723fc20d66f3f305f2008adeb279bf87462) ([#14091](https://www.github.com/tauri-apps/tauri/pull/14091)) Added a config to set a data_directory relative to the app-specific data dir in JavaScript and `tauri.conf.json`. + ## \[2.7.0] ### New Features diff --git a/crates/tauri-utils/Cargo.toml b/crates/tauri-utils/Cargo.toml index 939cb93ed..6ce1271a0 100644 --- a/crates/tauri-utils/Cargo.toml +++ b/crates/tauri-utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri-utils" -version = "2.7.0" +version = "2.8.1" description = "Utilities for Tauri" exclude = ["CHANGELOG.md", "/target"] readme = "README.md" @@ -57,6 +57,7 @@ swift-rs = { version = "1", optional = true, features = ["build"] } [dev-dependencies] getrandom = { version = "0.3", features = ["std"] } serial_test = "3" +tauri = { path = "../tauri" } [features] build = [ diff --git a/crates/tauri-utils/src/acl/build.rs b/crates/tauri-utils/src/acl/build.rs index d43afc281..44867f3f9 100644 --- a/crates/tauri-utils/src/acl/build.rs +++ b/crates/tauri-utils/src/acl/build.rs @@ -91,7 +91,8 @@ pub fn define_permissions bool>( let pkg_name_valid_path = pkg_name.replace(':', "-"); let permission_files_path = out_dir.join(format!("{pkg_name_valid_path}-permission-files")); let permission_files_json = serde_json::to_string(&permission_files)?; - fs::write(&permission_files_path, permission_files_json) + + write_if_changed(&permission_files_path, permission_files_json) .map_err(|e| Error::WriteFile(e, permission_files_path.clone()))?; if let Some(plugin_name) = pkg_name.strip_prefix("tauri:") { @@ -151,7 +152,8 @@ pub fn define_global_scope_schema( out_dir: &Path, ) -> Result<(), Error> { let path = out_dir.join("global-scope.json"); - fs::write(&path, serde_json::to_vec(&schema)?).map_err(|e| Error::WriteFile(e, path.clone()))?; + write_if_changed(&path, serde_json::to_vec(&schema)?) + .map_err(|e| Error::WriteFile(e, path.clone()))?; if let Some(plugin_name) = pkg_name.strip_prefix("tauri:") { println!( diff --git a/crates/tauri-utils/src/acl/mod.rs b/crates/tauri-utils/src/acl/mod.rs index 4d2322c39..03c33d4fd 100644 --- a/crates/tauri-utils/src/acl/mod.rs +++ b/crates/tauri-utils/src/acl/mod.rs @@ -50,7 +50,7 @@ pub const PERMISSION_SCHEMA_FILE_NAME: &str = "schema.json"; pub const APP_ACL_KEY: &str = "__app-acl__"; /// Known acl manifests file pub const ACL_MANIFESTS_FILE_NAME: &str = "acl-manifests.json"; -/// Known capabilityies file +/// Known capabilities file pub const CAPABILITIES_FILE_NAME: &str = "capabilities.json"; /// Allowed commands file name pub const ALLOWED_COMMANDS_FILE_NAME: &str = "allowed-commands.json"; diff --git a/crates/tauri-utils/src/acl/schema.rs b/crates/tauri-utils/src/acl/schema.rs index 56b50a5f6..3bb7ecff5 100644 --- a/crates/tauri-utils/src/acl/schema.rs +++ b/crates/tauri-utils/src/acl/schema.rs @@ -194,7 +194,7 @@ impl<'a> PermissionSchemaGenerator<'a, Iter<'a, PermissionSet>, Iter<'a, Permiss } } -/// Collect and include all possible identifiers in `Identifier` defintion in the schema +/// Collect and include all possible identifiers in `Identifier` definition in the schema fn extend_identifier_schema(schema: &mut RootSchema, acl: &BTreeMap) { if let Some(Schema::Object(identifier_schema)) = schema.definitions.get_mut("Identifier") { let permission_schemas = acl @@ -214,9 +214,9 @@ fn extend_identifier_schema(schema: &mut RootSchema, acl: &BTreeMap>( let schema_str = serde_json::to_string_pretty(&schema)?; + // FIXME: in schemars@v1 this doesn't seem to be necessary anymore. If it is, find a better solution. + let schema_str = schema_str.replace("\\r\\n", "\\n"); + let out_dir = out_dir.as_ref().join(PERMISSION_SCHEMAS_FOLDER_NAME); fs::create_dir_all(&out_dir).map_err(|e| Error::CreateDir(e, out_dir.clone()))?; diff --git a/crates/tauri-utils/src/config.rs b/crates/tauri-utils/src/config.rs index b3ead0269..8cd30bf5c 100644 --- a/crates/tauri-utils/src/config.rs +++ b/crates/tauri-utils/src/config.rs @@ -208,9 +208,10 @@ impl<'de> Deserialize<'de> for BundleType { } /// Targets to bundle. Each value is case insensitive. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Default)] pub enum BundleTarget { /// Bundle all targets. + #[default] All, /// A list of bundle targets. List(Vec), @@ -257,12 +258,6 @@ impl schemars::JsonSchema for BundleTarget { } } -impl Default for BundleTarget { - fn default() -> Self { - Self::All - } -} - impl Serialize for BundleTarget { fn serialize(&self, serializer: S) -> std::result::Result where @@ -773,7 +768,7 @@ pub struct WixConfig { /// Because a valid version is required for MSI installer, it will be derived from [`Config::version`] if this field is not set. /// /// The first field is the major version and has a maximum value of 255. The second field is the minor version and has a maximum value of 255. - /// The third and foruth fields have a maximum value of 65,535. + /// The third and fourth fields have a maximum value of 65,535. /// /// See for more info. pub version: Option, @@ -834,7 +829,7 @@ pub struct WixConfig { /// Compression algorithms used in the NSIS installer. /// /// See -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)] #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub enum NsisCompression { @@ -843,19 +838,14 @@ pub enum NsisCompression { /// BZIP2 usually gives better compression ratios than ZLIB, but it is a bit slower and uses more memory. With the default compression level it uses about 4 MB of memory. Bzip2, /// LZMA (default) is a new compression method that gives very good compression ratios. The decompression speed is high (10-20 MB/s on a 2 GHz CPU), the compression speed is lower. The memory size that will be used for decompression is the dictionary size plus a few KBs, the default is 8 MB. + #[default] Lzma, /// Disable compression None, } -impl Default for NsisCompression { - fn default() -> Self { - Self::Lzma - } -} - /// Install Modes for the NSIS installer. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +#[derive(Default, Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum NSISInstallerMode { @@ -864,6 +854,7 @@ pub enum NSISInstallerMode { /// Install the app by default in a directory that doesn't require Administrator access. /// /// Installer metadata will be saved under the `HKCU` registry path. + #[default] CurrentUser, /// Install the app by default in the `Program Files` folder directory requires Administrator /// access for the installation. @@ -878,12 +869,6 @@ pub enum NSISInstallerMode { Both, } -impl Default for NSISInstallerMode { - fn default() -> Self { - Self::CurrentUser - } -} - /// Configuration for the Installer bundle using NSIS. #[derive(Debug, Default, PartialEq, Eq, Clone, Deserialize, Serialize)] #[cfg_attr(feature = "schema", derive(JsonSchema))] @@ -1040,7 +1025,7 @@ pub enum CustomSignCommandConfig { /// This is a simpler notation for the command. /// Tauri will split the string with `' '` and use the first element as the command name and the rest as arguments. /// - /// If you need to use whitespace in the command or arguments, use the object notation [`Self::ScriptWithOptions`]. + /// If you need to use whitespace in the command or arguments, use the object notation [`Self::CommandWithOptions`]. Command(String), /// An object notation of the command. /// @@ -1637,9 +1622,9 @@ pub struct WindowEffectsConfig { #[cfg_attr(feature = "schema", derive(JsonSchema))] #[serde(rename_all = "camelCase", deny_unknown_fields)] pub struct PreventOverflowMargin { - /// Horizontal margin in physical unit + /// Horizontal margin in physical pixels pub width: u32, - /// Vertical margin in physical unit + /// Vertical margin in physical pixels pub height: u32, } @@ -1697,7 +1682,7 @@ pub struct WindowConfig { /// ```rust /// tauri::Builder::default() /// .setup(|app| { - /// tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?; + /// tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?; /// Ok(()) /// }); /// ``` @@ -1717,26 +1702,26 @@ pub struct WindowConfig { /// Whether or not the window starts centered or not. #[serde(default)] pub center: bool, - /// The horizontal position of the window's top left corner + /// The horizontal position of the window's top left corner in logical pixels pub x: Option, - /// The vertical position of the window's top left corner + /// The vertical position of the window's top left corner in logical pixels pub y: Option, - /// The window width. + /// The window width in logical pixels. #[serde(default = "default_width")] pub width: f64, - /// The window height. + /// The window height in logical pixels. #[serde(default = "default_height")] pub height: f64, - /// The min window width. + /// The min window width in logical pixels. #[serde(alias = "min-width")] pub min_width: Option, - /// The min window height. + /// The min window height in logical pixels. #[serde(alias = "min-height")] pub min_height: Option, - /// The max window width. + /// The max window width in logical pixels. #[serde(alias = "max-width")] pub max_width: Option, - /// The max window height. + /// The max window height in logical pixels. #[serde(alias = "max-height")] pub max_height: Option, /// Whether or not to prevent the window from overflowing the workarea @@ -2050,7 +2035,7 @@ impl Default for WindowConfig { closable: true, title: default_title(), fullscreen: false, - focus: false, + focus: true, focusable: true, transparent: false, maximized: false, @@ -2255,8 +2240,8 @@ impl Default for DisabledCspModificationKind { /// Each pattern can start with a variable that resolves to a system base directory. /// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, /// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, -/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, -/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`. +/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$TEMP`, +/// `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`. #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] #[serde(untagged)] #[cfg_attr(feature = "schema", derive(JsonSchema))] @@ -2714,11 +2699,12 @@ impl<'de> Deserialize<'de> for CapabilityEntry { /// The application pattern. #[skip_serializing_none] -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "lowercase", tag = "use", content = "options")] #[cfg_attr(feature = "schema", derive(JsonSchema))] pub enum PatternKind { /// Brownfield pattern. + #[default] Brownfield, /// Isolation pattern. Recommended for security purposes. Isolation { @@ -2727,12 +2713,6 @@ pub enum PatternKind { }, } -impl Default for PatternKind { - fn default() -> Self { - Self::Brownfield - } -} - /// The App configuration object. /// /// See more: @@ -2791,7 +2771,7 @@ pub struct AppConfig { /// ```rust /// tauri::Builder::default() /// .setup(|app| { - /// tauri::WebviewWindowBuilder::from_config(app.handle(), app.config().app.windows[0])?.build()?; + /// tauri::WebviewWindowBuilder::from_config(app.handle(), &app.config().app.windows[0])?.build()?; /// Ok(()) /// }); /// ``` @@ -2958,6 +2938,16 @@ pub struct AndroidConfig { #[serde(alias = "version-code")] #[cfg_attr(feature = "schema", validate(range(min = 1, max = 2_100_000_000)))] pub version_code: Option, + + /// Whether to automatically increment the `versionCode` on each build. + /// + /// - If `true`, the generator will try to read the last `versionCode` from + /// `tauri.properties` and increment it by 1 for every build. + /// - If `false` or not set, it falls back to `version_code` or semver-derived logic. + /// + /// Note that to use this feature, you should remove `/tauri.properties` from `src-tauri/gen/android/app/.gitignore` so the current versionCode is committed to the repository. + #[serde(alias = "auto-increment-version-code", default)] + pub auto_increment_version_code: bool, } impl Default for AndroidConfig { @@ -2965,6 +2955,7 @@ impl Default for AndroidConfig { Self { min_sdk_version: default_min_sdk_version(), version_code: None, + auto_increment_version_code: false, } } } @@ -2979,11 +2970,11 @@ fn default_min_sdk_version() -> u32 { #[serde(untagged, deny_unknown_fields)] #[non_exhaustive] pub enum FrontendDist { - /// An external URL that should be used as the default application URL. + /// An external URL that should be used as the default application URL. No assets are embedded in the app in this case. Url(Url), /// Path to a directory containing the frontend dist assets. Directory(PathBuf), - /// An array of files to embed on the app. + /// An array of files to embed in the app. Files(Vec), } @@ -3202,18 +3193,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(), )) } @@ -4422,4 +4415,12 @@ mod test { assert!(object_json.contains("\"cwd\":null") || !object_json.contains("cwd")); assert!(object_json.contains("\"args\":null") || !object_json.contains("args")); } + + #[test] + fn window_config_default_same_as_deserialize() { + let config_from_deserialization: WindowConfig = serde_json::from_str("{}").unwrap(); + let config_from_default: WindowConfig = WindowConfig::default(); + + assert_eq!(config_from_deserialization, config_from_default); + } } diff --git a/crates/tauri-utils/src/config/parse.rs b/crates/tauri-utils/src/config/parse.rs index f904d5f25..df79a32c9 100644 --- a/crates/tauri-utils/src/config/parse.rs +++ b/crates/tauri-utils/src/config/parse.rs @@ -209,7 +209,7 @@ pub fn read_platform( /// JSON with `.json`. pub fn does_supported_file_name_exist(target: Target, path: impl Into) -> bool { let path = path.into(); - let source_file_name = path.file_name().unwrap().to_str().unwrap(); + let source_file_name = path.file_name().unwrap(); let lookup_platform_config = ENABLED_FORMATS .iter() .any(|format| source_file_name == format.into_platform_file_name(target)); diff --git a/crates/tauri-utils/src/config_v1/mod.rs b/crates/tauri-utils/src/config_v1/mod.rs index 5fc9450d9..a8a5fc2e5 100644 --- a/crates/tauri-utils/src/config_v1/mod.rs +++ b/crates/tauri-utils/src/config_v1/mod.rs @@ -131,9 +131,10 @@ impl<'de> Deserialize<'de> for BundleType { } /// Targets to bundle. Each value is case insensitive. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Default)] pub enum BundleTarget { /// Bundle all targets. + #[default] All, /// A list of bundle targets. List(Vec), @@ -251,12 +252,6 @@ impl schemars::JsonSchema for BundleTarget { } } -impl Default for BundleTarget { - fn default() -> Self { - Self::All - } -} - impl Serialize for BundleTarget { fn serialize(&self, serializer: S) -> std::result::Result where @@ -552,7 +547,7 @@ pub struct NsisConfig { } /// Install Modes for the NSIS installer. -#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Copy, Serialize, Deserialize, Default)] #[serde(rename_all = "camelCase", deny_unknown_fields)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum NSISInstallerMode { @@ -561,6 +556,7 @@ pub enum NSISInstallerMode { /// Install the app by default in a directory that doesn't require Administrator access. /// /// Installer metadata will be saved under the `HKCU` registry path. + #[default] CurrentUser, /// Install the app by default in the `Program Files` folder directory requires Administrator /// access for the installation. @@ -575,12 +571,6 @@ pub enum NSISInstallerMode { Both, } -impl Default for NSISInstallerMode { - fn default() -> Self { - Self::CurrentUser - } -} - /// Install modes for the Webview2 runtime. /// Note that for the updater bundle [`Self::DownloadBootstrapper`] is used. /// @@ -2393,11 +2383,12 @@ impl Allowlist for AllowlistConfig { /// The application pattern. #[skip_serializing_none] -#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize)] +#[derive(Debug, PartialEq, Eq, Clone, Serialize, Deserialize, Default)] #[serde(rename_all = "lowercase", tag = "use", content = "options")] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum PatternKind { /// Brownfield pattern. + #[default] Brownfield, /// Isolation pattern. Recommended for security purposes. Isolation { @@ -2406,12 +2397,6 @@ pub enum PatternKind { }, } -impl Default for PatternKind { - fn default() -> Self { - Self::Brownfield - } -} - /// The Tauri configuration object. /// /// See more: https://tauri.app/v1/api/config#tauriconfig @@ -2481,7 +2466,7 @@ impl<'de> Deserialize<'de> for UpdaterEndpoint { } /// Install modes for the Windows update. -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, Default)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schema", schemars(rename_all = "camelCase"))] pub enum WindowsUpdateInstallMode { @@ -2491,6 +2476,7 @@ pub enum WindowsUpdateInstallMode { /// Requires admin privileges if the installer does. Quiet, /// Specifies unattended mode, which means the installation only shows a progress bar. + #[default] Passive, // to add more modes, we need to check if the updater relaunch makes sense // i.e. for a full UI mode, the user can also mark the installer to start the app @@ -2510,12 +2496,6 @@ impl Display for WindowsUpdateInstallMode { } } -impl Default for WindowsUpdateInstallMode { - fn default() -> Self { - Self::Passive - } -} - impl Serialize for WindowsUpdateInstallMode { fn serialize(&self, serializer: S) -> std::result::Result where @@ -2989,10 +2969,11 @@ fn default_build() -> BuildConfig { } /// How the window title bar should be displayed on macOS. -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, Default)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] pub enum TitleBarStyle { /// A normal title bar. + #[default] Visible, /// Makes the title bar transparent, so the window background color is shown instead. /// @@ -3007,12 +2988,6 @@ pub enum TitleBarStyle { Overlay, } -impl Default for TitleBarStyle { - fn default() -> Self { - Self::Visible - } -} - impl Serialize for TitleBarStyle { fn serialize(&self, serializer: S) -> std::result::Result where diff --git a/crates/tauri-utils/src/html.rs b/crates/tauri-utils/src/html.rs index bfa203f00..958ce5978 100644 --- a/crates/tauri-utils/src/html.rs +++ b/crates/tauri-utils/src/html.rs @@ -211,21 +211,16 @@ impl From<&PatternKind> for PatternObject { } /// Where the JavaScript is injected to -#[derive(Debug, Serialize)] +#[derive(Debug, Serialize, Default)] #[serde(rename_all = "lowercase")] pub enum IsolationSide { /// Original frame, the Brownfield application + #[default] Original, /// Secure frame, the isolation security application Secure, } -impl Default for IsolationSide { - fn default() -> Self { - Self::Original - } -} - /// Injects the Isolation JavaScript to a codegen time document. /// /// Note: This function is not considered part of the stable API. @@ -286,6 +281,38 @@ pub fn inline_isolation(document: &NodeRef, dir: &Path) { } } +/// Normalize line endings in script content to match what the browser uses for CSP hashing. +/// +/// According to the HTML spec, browsers normalize: +/// - `\r\n` → `\n` +/// - `\r` → `\n` +pub fn normalize_script_for_csp(input: &[u8]) -> Vec { + let mut output = Vec::with_capacity(input.len()); + + let mut i = 0; + while i < input.len() { + match input[i] { + b'\r' => { + if i + 1 < input.len() && input[i + 1] == b'\n' { + // CRLF → LF + output.push(b'\n'); + i += 2; + } else { + // Lone CR → LF + output.push(b'\n'); + i += 1; + } + } + _ => { + output.push(input[i]); + i += 1; + } + } + } + + output +} + #[cfg(test)] mod tests { @@ -307,4 +334,14 @@ mod tests { ); } } + + #[test] + fn normalize_script_for_csp() { + let js = "// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\r// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\r\n\r\nwindow.__TAURI_ISOLATION_HOOK__ = (payload, options) => {\r\n return payload\r\n}\r\n"; + let expected = "// Copyright 2019-2024 Tauri Programme within The Commons Conservancy\n// SPDX-License-Identifier: Apache-2.0\n// SPDX-License-Identifier: MIT\n\nwindow.__TAURI_ISOLATION_HOOK__ = (payload, options) => {\n return payload\n}\n"; + assert_eq!( + super::normalize_script_for_csp(js.as_bytes()), + expected.as_bytes() + ) + } } diff --git a/crates/tauri-utils/src/lib.rs b/crates/tauri-utils/src/lib.rs index b8c41bca9..25e5a4f97 100644 --- a/crates/tauri-utils/src/lib.rs +++ b/crates/tauri-utils/src/lib.rs @@ -112,13 +112,13 @@ mod window_effects { UnderWindowBackground, /// **macOS 10.14+** UnderPageBackground, - /// Mica effect that matches the system dark perefence **Windows 11 Only** + /// Mica effect that matches the system dark preference **Windows 11 Only** Mica, /// Mica effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only** MicaDark, /// Mica effect with light mode **Windows 11 Only** MicaLight, - /// Tabbed effect that matches the system dark perefence **Windows 11 Only** + /// Tabbed effect that matches the system dark preference **Windows 11 Only** Tabbed, /// Tabbed effect with dark mode but only if dark mode is enabled on the system **Windows 11 Only** TabbedDark, @@ -157,11 +157,12 @@ mod window_effects { pub use window_effects::{WindowEffect, WindowEffectState}; /// How the window title bar should be displayed on macOS. -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, Default)] #[cfg_attr(feature = "schema", derive(schemars::JsonSchema))] #[non_exhaustive] pub enum TitleBarStyle { /// A normal title bar. + #[default] Visible, /// Makes the title bar transparent, so the window background color is shown instead. /// @@ -176,12 +177,6 @@ pub enum TitleBarStyle { Overlay, } -impl Default for TitleBarStyle { - fn default() -> Self { - Self::Visible - } -} - impl Serialize for TitleBarStyle { fn serialize(&self, serializer: S) -> std::result::Result where @@ -372,7 +367,7 @@ pub enum Error { #[cfg(feature = "resources")] #[error("could not walk directory `{0}`, try changing `allow_walk` to true on the `ResourcePaths` constructor.")] NotAllowedToWalkDir(std::path::PathBuf), - /// Resourece path doesn't exist + /// Resource path doesn't exist #[cfg(feature = "resources")] #[error("resource path `{0}` doesn't exist")] ResourcePathNotFound(std::path::PathBuf), diff --git a/crates/tauri-utils/src/platform.rs b/crates/tauri-utils/src/platform.rs index 1142af5e3..6eaaf3ffe 100644 --- a/crates/tauri-utils/src/platform.rs +++ b/crates/tauri-utils/src/platform.rs @@ -238,16 +238,12 @@ const CARGO_OUTPUT_DIRECTORIES: &[&str] = &["debug", "release", "custom-profile" #[cfg(test)] fn is_cargo_output_directory(path: &std::path::Path) -> bool { - let last_component = path - .components() - .next_back() - .unwrap() - .as_os_str() - .to_str() - .unwrap(); + let Some(last_component) = path.components().next_back() else { + return false; + }; CARGO_OUTPUT_DIRECTORIES .iter() - .any(|dirname| &last_component == dirname) + .any(|dirname| &last_component.as_os_str() == dirname) } /// Computes the resource directory of the current environment. @@ -348,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` becuase it could get optimized away without it, +// 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-utils/src/resources.rs b/crates/tauri-utils/src/resources.rs index 414815e2b..dfba0746c 100644 --- a/crates/tauri-utils/src/resources.rs +++ b/crates/tauri-utils/src/resources.rs @@ -97,9 +97,7 @@ impl<'a> ResourcePaths<'a> { iter: ResourcePathsIter { pattern_iter: PatternIter::Slice(patterns.iter()), allow_walk, - current_path: None, current_pattern: None, - current_dest: None, walk_iter: None, glob_iter: None, }, @@ -112,9 +110,7 @@ impl<'a> ResourcePaths<'a> { iter: ResourcePathsIter { pattern_iter: PatternIter::Map(patterns.iter()), allow_walk, - current_path: None, current_pattern: None, - current_dest: None, walk_iter: None, glob_iter: None, }, @@ -136,13 +132,9 @@ pub struct ResourcePathsIter<'a> { /// whether the resource paths allows directories or not. allow_walk: bool, - current_path: Option, - /// The key of map when `pattern_iter` is a [`PatternIter::Map`], + /// The (key, value) of map when `pattern_iter` is a [`PatternIter::Map`], /// used for determining [`Resource::target`] - current_pattern: Option, - /// The value of the map when `pattern_iter` is a [`PatternIter::Map`], - /// used for determining [`Resource::target`] - current_dest: Option, + current_pattern: Option<(String, PathBuf)>, walk_iter: Option, glob_iter: Option, @@ -157,8 +149,7 @@ impl ResourcePathsIter<'_> { Err(err) => return Some(Err(err.into())), }; - self.current_path = Some(normalize(&entry)); - self.next_current_path() + self.next_current_path(normalize(&entry)) } fn next_walk_iter(&mut self) -> Option> { @@ -169,8 +160,7 @@ impl ResourcePathsIter<'_> { Err(err) => return Some(Err(err.into())), }; - self.current_path = Some(normalize(entry.path())); - self.next_current_path() + self.next_current_path(normalize(entry.path())) } fn resource_from_path(&mut self, path: &Path) -> crate::Result { @@ -180,12 +170,11 @@ impl ResourcePathsIter<'_> { Ok(Resource { path: path.to_path_buf(), - target: if let Some(current_dest) = &self.current_dest { + target: if let Some((pattern, dest)) = &self.current_pattern { // if processing a directory, preserve directory structure under current_dest if self.walk_iter.is_some() { - let current_pattern = self.current_pattern.as_ref().unwrap(); - current_dest.join(path.strip_prefix(current_pattern).unwrap_or(path)) - } else if current_dest.components().count() == 0 { + dest.join(path.strip_prefix(pattern).unwrap_or(path)) + } else if dest.components().count() == 0 { // if current_dest is empty while processing a file pattern or glob // we preserve the file name as it is PathBuf::from(path.file_name().unwrap()) @@ -193,9 +182,9 @@ impl ResourcePathsIter<'_> { // if processing a glob and current_dest is not empty // we put all globbed paths under current_dest // preserving the file name as it is - current_dest.join(path.file_name().unwrap()) + dest.join(path.file_name().unwrap()) } else { - current_dest.clone() + dest.clone() } } else { // If `pattern_iter` is a [`PatternIter::Slice`] @@ -204,11 +193,7 @@ impl ResourcePathsIter<'_> { }) } - fn next_current_path(&mut self) -> Option> { - // should be safe to unwrap since every call to `self.next_current_path()` - // is preceeded with assignemt to `self.current_path` - let path = self.current_path.take().unwrap(); - + fn next_current_path(&mut self, path: PathBuf) -> Option> { let is_dir = path.is_dir(); if is_dir { @@ -238,15 +223,12 @@ impl ResourcePathsIter<'_> { fn next_pattern(&mut self) -> Option> { self.current_pattern = None; - self.current_dest = None; - self.current_path = None; let pattern = match &mut self.pattern_iter { PatternIter::Slice(iter) => iter.next()?, PatternIter::Map(iter) => { let (pattern, dest) = iter.next()?; - self.current_pattern = Some(pattern.clone()); - self.current_dest = Some(resource_relpath(Path::new(dest))); + self.current_pattern = Some((pattern.clone(), resource_relpath(Path::new(dest)))); pattern } }; @@ -265,8 +247,7 @@ impl ResourcePathsIter<'_> { } } - self.current_path = Some(normalize(Path::new(pattern))); - self.next_current_path() + self.next_current_path(normalize(Path::new(pattern))) } } @@ -282,10 +263,6 @@ impl Iterator for ResourcePathsIter<'_> { type Item = crate::Result; fn next(&mut self) -> Option> { - if self.current_path.is_some() { - return self.next_current_path(); - } - if self.walk_iter.is_some() { match self.next_walk_iter() { Some(r) => return Some(r), diff --git a/crates/tauri-utils/src/tokens.rs b/crates/tauri-utils/src/tokens.rs index c02fb1fdc..3c566a377 100644 --- a/crates/tauri-utils/src/tokens.rs +++ b/crates/tauri-utils/src/tokens.rs @@ -27,7 +27,7 @@ macro_rules! literal_struct { /// Create a `String` constructor `TokenStream`. /// -/// e.g. `"Hello World" -> String::from("Hello World"). +/// e.g. `"Hello World"` -> `String::from("Hello World")`. /// This takes a `&String` to reduce casting all the `&String` -> `&str` manually. pub fn str_lit(s: impl AsRef) -> TokenStream { let s = s.as_ref(); diff --git a/crates/tauri/CHANGELOG.md b/crates/tauri/CHANGELOG.md index 695022218..ea3c1568c 100644 --- a/crates/tauri/CHANGELOG.md +++ b/crates/tauri/CHANGELOG.md @@ -1,5 +1,83 @@ # Changelog +## \[2.9.5] + +### Bug Fixes + +- [`251203b89`](https://www.github.com/tauri-apps/tauri/commit/251203b8963419cb3b40741767393e8f3c909ef9) ([#14637](https://www.github.com/tauri-apps/tauri/pull/14637) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix `Monitor::work_area` returns logical position and size inside the `PhysicalRect` on Linux + +### Dependencies + +- Upgraded to `tauri-runtime-wry@2.9.3` + +## \[2.9.4] + +### Performance Improvements + +- [`ce98d87ce`](https://www.github.com/tauri-apps/tauri/commit/ce98d87ce0aaa907285852eb80691197424e03c3) ([#14474](https://www.github.com/tauri-apps/tauri/pull/14474) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) refactor: remove needless collect. No user facing changes. +- [`ee3cc4a91`](https://www.github.com/tauri-apps/tauri/commit/ee3cc4a91bf1315ecaefe90f423ffd55ef6c40db) ([#14475](https://www.github.com/tauri-apps/tauri/pull/14475) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) perf: remove needless clones in various files for improved performance. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-utils@2.8.1` +- Upgraded to `tauri-runtime@2.9.2` +- Upgraded to `tauri-runtime-wry@2.9.2` +- Upgraded to `tauri-macros@2.5.2` +- Upgraded to `tauri-build@2.5.3` + +## \[2.9.3] + +### Bug Fixes + +- [`4b00130b8`](https://www.github.com/tauri-apps/tauri/commit/4b00130b86a27b6f121bf57897b5e92d83bcc0fc) ([#14385](https://www.github.com/tauri-apps/tauri/pull/14385) by [@lucasfernog](https://www.github.com/tauri-apps/tauri/../../lucasfernog)) Fix iOS deadlock when running on the simulator from Xcode by properly piping stdout/stderr messages through the Xcode console and OSLog. + +### Dependencies + +- Upgraded to `tauri-macros@2.5.1` +- Upgraded to `tauri-build@2.5.2` + +## \[2.9.2] + +### Bug Fixes + +- [`28b9e7c7b`](https://www.github.com/tauri-apps/tauri/commit/28b9e7c7b83845c35fe46c37e8ed8e9022b4634e) ([#14377](https://www.github.com/tauri-apps/tauri/pull/14377) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fix `undefined is not an object (evaluating '[callbackId, data]')` error on custom protocol IPC fails + +## \[2.9.1] + +### Bug Fixes + +- [`4b6b8690a`](https://www.github.com/tauri-apps/tauri/commit/4b6b8690ab886ebdf1307951cffbe03e31280baa) ([#14347](https://www.github.com/tauri-apps/tauri/pull/14347) by [@FabianLars](https://www.github.com/tauri-apps/tauri/../../FabianLars)) Fixed an issue that caused docs.rs builds to fail. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-build@2.5.1` +- Upgraded to `tauri-runtime@2.9.1` +- Upgraded to `tauri-runtime-wry@2.9.1` + +## \[2.9.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scroll_bar_style` option to the Webview and WebviewWindow builders. + The possible values for this option are gated behind conditional compilation + flags, and will need to be applied using conditional compilation if customised. +- [`3397fd9bf`](https://www.github.com/tauri-apps/tauri/commit/3397fd9bfe5f6b1337110149f6c34731b8a44bb3) ([#14133](https://www.github.com/tauri-apps/tauri/pull/14133)) Added mobile app plugin to support exit and back button press event. +- [`68cb31897`](https://www.github.com/tauri-apps/tauri/commit/68cb318979317c09f401825150e007d60377e75e) ([#14328](https://www.github.com/tauri-apps/tauri/pull/14328)) Added `onStop`, `onDestroy`, `onRestart`, `onConfigurationChanged` Android plugin hooks. +- [`2e089f6ac`](https://www.github.com/tauri-apps/tauri/commit/2e089f6acb854e4d7f8eafb9b2f8242b1c9fa491) ([#14148](https://www.github.com/tauri-apps/tauri/pull/14148)) Support async Swift plugin methods (`completionHandler:`) in PluginManager + +### Bug Fixes + +- [`006d59283`](https://www.github.com/tauri-apps/tauri/commit/006d592837259cac87f15cf3ffc99e7fce97685e) ([#14260](https://www.github.com/tauri-apps/tauri/pull/14260)) Properly deserialize Android plugin args with key starting with `is` (previously treated as a getter instead of a field name). +- [`69476d8e2`](https://www.github.com/tauri-apps/tauri/commit/69476d8e2314b85bf46046140bc5495fe29b7d29) ([#14170](https://www.github.com/tauri-apps/tauri/pull/14170)) Fix the stack overflow when having too many commands in a single invoke handler in release build + +### Dependencies + +- Upgraded to `tauri-utils@2.8.0` +- Upgraded to `tauri-runtime-wry@2.9.0` +- Upgraded to `tauri-runtime@2.9.0` +- Upgraded to `tauri-build@2.5.0` +- Upgraded to `tauri-macros@2.5.0` + ## \[2.8.5] ### Enhancements diff --git a/crates/tauri/Cargo.toml b/crates/tauri/Cargo.toml index 7d453f8e7..6d3c9137c 100644 --- a/crates/tauri/Cargo.toml +++ b/crates/tauri/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "tauri" -version = "2.8.5" +version = "2.9.5" description = "Make tiny, secure apps for all desktop platforms with Tauri" exclude = ["/test", "/.scripts", "CHANGELOG.md", "/target"] readme = "README.md" @@ -25,9 +25,8 @@ features = [ "protocol-asset", "test", "specta", + "dynamic-acl", ] -rustc-args = ["--cfg", "docsrs"] -rustdoc-args = ["--cfg", "docsrs"] default-target = "x86_64-unknown-linux-gnu" targets = [ "x86_64-pc-windows-msvc", @@ -56,12 +55,12 @@ uuid = { version = "1", features = ["v4"], optional = true } url = "2" anyhow = "1" thiserror = "2" -tauri-runtime = { version = "2.8.0", path = "../tauri-runtime" } -tauri-macros = { version = "2.4.0", path = "../tauri-macros" } -tauri-utils = { version = "2.7.0", features = [ +tauri-runtime = { version = "2.9.2", path = "../tauri-runtime" } +tauri-macros = { version = "2.5.2", path = "../tauri-macros" } +tauri-utils = { version = "2.8.1", features = [ "resources", ], path = "../tauri-utils" } -tauri-runtime-wry = { version = "2.8.1", path = "../tauri-runtime-wry", default-features = false, optional = true } +tauri-runtime-wry = { version = "2.9.3", path = "../tauri-runtime-wry", default-features = false, optional = true } getrandom = "0.3" serde_repr = "0.1" http = "1" @@ -69,7 +68,6 @@ dirs = "6" percent-encoding = "2" raw-window-handle = { version = "0.6", features = ["std"] } glob = "0.3" -urlpattern = "0.3" mime = "0.3" data-url = { version = "0.3", optional = true } serialize-to-javascript = "0.1.2" @@ -99,7 +97,7 @@ tray-icon = { version = "0.21", default-features = false, features = [ # linux [target.'cfg(any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd", target_os = "openbsd", target_os = "netbsd"))'.dependencies] gtk = { version = "0.18", features = ["v3_24"] } -webkit2gtk = { version = "=2.0.1", features = ["v2_40"], optional = true } +webkit2gtk = { version = "=2.0.2", features = ["v2_40"], optional = true } # darwin [target.'cfg(target_vendor = "apple")'.dependencies] @@ -143,11 +141,13 @@ windows = { version = "0.61", features = [ # mobile [target.'cfg(any(target_os = "android", all(target_vendor = "apple", not(target_os = "macos"))))'.dependencies] bytes = { version = "1", features = ["serde"] } -reqwest = { version = "0.12", default-features = false, features = [ +reqwest = { version = "0.13", default-features = false, features = [ "json", "stream", - ] } +rustls = { version = "0.23", default-features = false, features = [ + "ring", +], optional = true } # android [target.'cfg(target_os = "android")'.dependencies] @@ -164,8 +164,8 @@ objc2-ui-kit = { version = "0.3.0", default-features = false, features = [ [build-dependencies] glob = "0.3" heck = "0.5" -tauri-build = { path = "../tauri-build/", default-features = false, version = "2.4.1" } -tauri-utils = { path = "../tauri-utils/", version = "2.7.0", features = [ +tauri-build = { path = "../tauri-build/", default-features = false, version = "2.5.3" } +tauri-utils = { path = "../tauri-utils/", version = "2.8.1", features = [ "build", ] } @@ -200,10 +200,9 @@ linux-libxdo = ["tray-icon/libxdo", "muda/libxdo"] isolation = ["tauri-utils/isolation", "tauri-macros/isolation", "uuid"] custom-protocol = ["tauri-macros/custom-protocol"] # TODO: Remove these flags in v3 and/or enable them by default behind a mobile flag https://github.com/tauri-apps/tauri/issues/12384 -# For now those feature flags keep enabling reqwest features in case some users depend on that by accident. native-tls = ["reqwest/native-tls"] native-tls-vendored = ["reqwest/native-tls-vendored"] -rustls-tls = ["reqwest/rustls-tls"] +rustls-tls = ["reqwest/rustls-no-provider", "dep:rustls"] devtools = ["tauri-runtime/devtools", "tauri-runtime-wry?/devtools"] process-relaunch-dangerous-allow-symlink-macos = [ "tauri-utils/process-relaunch-dangerous-allow-symlink-macos", diff --git a/crates/tauri/build.rs b/crates/tauri/build.rs index 4248728b5..d63401ed0 100644 --- a/crates/tauri/build.rs +++ b/crates/tauri/build.rs @@ -164,6 +164,8 @@ const PLUGINS: &[(&str, &[(&str, bool)])] = &[ ("set_app_theme", false), ("set_dock_visibility", false), ("bundle_type", true), + ("register_listener", true), + ("remove_listener", true), ], ), ( diff --git a/crates/tauri/mobile/android-codegen/TauriActivity.kt b/crates/tauri/mobile/android-codegen/TauriActivity.kt index 1b3fb7b0f..1c96394b8 100644 --- a/crates/tauri/mobile/android-codegen/TauriActivity.kt +++ b/crates/tauri/mobile/android-codegen/TauriActivity.kt @@ -6,12 +6,13 @@ package {{package}} -import android.os.Bundle import android.content.Intent +import android.content.res.Configuration import app.tauri.plugin.PluginManager abstract class TauriActivity : WryActivity() { var pluginManager: PluginManager = PluginManager(this) + override val handleBackNavigation: Boolean = false override fun onNewIntent(intent: Intent) { super.onNewIntent(intent) @@ -27,4 +28,24 @@ abstract class TauriActivity : WryActivity() { super.onPause() pluginManager.onPause() } + + override fun onRestart() { + super.onRestart() + pluginManager.onRestart() + } + + override fun onStop() { + super.onStop() + pluginManager.onStop() + } + + override fun onDestroy() { + super.onDestroy() + pluginManager.onDestroy() + } + + override fun onConfigurationChanged(newConfig: Configuration) { + super.onConfigurationChanged(newConfig) + pluginManager.onConfigurationChanged(newConfig) + } } diff --git a/crates/tauri/mobile/android/src/main/java/app/tauri/AppPlugin.kt b/crates/tauri/mobile/android/src/main/java/app/tauri/AppPlugin.kt new file mode 100644 index 000000000..0c2dc71f7 --- /dev/null +++ b/crates/tauri/mobile/android/src/main/java/app/tauri/AppPlugin.kt @@ -0,0 +1,54 @@ +// Copyright 2019-2024 Tauri Programme within The Commons Conservancy +// SPDX-License-Identifier: Apache-2.0 +// SPDX-License-Identifier: MIT + +package app.tauri + +import android.app.Activity +import android.webkit.WebView +import androidx.activity.OnBackPressedCallback +import androidx.appcompat.app.AppCompatActivity +import app.tauri.annotation.Command +import app.tauri.annotation.TauriPlugin +import app.tauri.plugin.Plugin +import app.tauri.plugin.Invoke +import app.tauri.plugin.JSObject + +@TauriPlugin +class AppPlugin(private val activity: Activity): Plugin(activity) { + private val BACK_BUTTON_EVENT = "back-button" + + private var webView: WebView? = null + + override fun load(webView: WebView) { + this.webView = webView + } + + init { + val callback = object : OnBackPressedCallback(true) { + override fun handleOnBackPressed() { + if (!hasListener(BACK_BUTTON_EVENT)) { + if (this@AppPlugin.webView?.canGoBack() == true) { + this@AppPlugin.webView!!.goBack() + } else { + this.isEnabled = false + this@AppPlugin.activity.onBackPressed() + this.isEnabled = true + } + } else { + val data = JSObject().apply { + put("canGoBack", this@AppPlugin.webView?.canGoBack() ?: false) + } + trigger(BACK_BUTTON_EVENT, data) + } + } + } + (activity as AppCompatActivity).onBackPressedDispatcher.addCallback(activity, callback) + } + + @Command + fun exit(invoke: Invoke) { + invoke.resolve() + activity.finish() + } +} diff --git a/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt b/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt index 3a6cde9bf..d33fa8a4d 100644 --- a/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt +++ b/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/Plugin.kt @@ -5,10 +5,10 @@ package app.tauri.plugin import android.app.Activity +import android.content.res.Configuration import android.content.Intent import android.content.pm.PackageManager import android.net.Uri -import android.os.Bundle import android.webkit.WebView import androidx.activity.result.IntentSenderRequest import androidx.core.app.ActivityCompat @@ -22,7 +22,6 @@ import app.tauri.annotation.InvokeArg import app.tauri.annotation.PermissionCallback import app.tauri.annotation.TauriPlugin import com.fasterxml.jackson.databind.ObjectMapper -import org.json.JSONException import java.util.* import java.util.concurrent.CopyOnWriteArrayList @@ -72,6 +71,28 @@ abstract class Plugin(private val activity: Activity) { */ open fun onResume() {} + /** + * This event is called after onStop() when the current activity is being re-displayed to the user (the user has navigated back to it). + * It will be followed by onStart() and then onResume(). + */ + open fun onRestart() {} + + /** + * This event is called when the app is no longer visible to the user. + * You will next receive either onRestart(), onDestroy(), or nothing, depending on later user activity. + */ + open fun onStop() {} + + /** + * This event is called before the activity is destroyed. + */ + open fun onDestroy() {} + + /** + * This event is called when a configuration change occurs but the app does not recreate the activity. + */ + open fun onConfigurationChanged(newConfig: Configuration) {} + /** * Start activity for result with the provided Intent and resolve calling the provided callback method name. * @@ -148,6 +169,10 @@ abstract class Plugin(private val activity: Activity) { } } + fun hasListener(event: String): Boolean { + return !listeners[event].isNullOrEmpty() + } + @Command open fun registerListener(invoke: Invoke) { val args = invoke.parseArgs(RegisterListenerArgs::class.java) diff --git a/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginManager.kt b/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginManager.kt index 6e6d0f604..362896b70 100644 --- a/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginManager.kt +++ b/crates/tauri/mobile/android/src/main/java/app/tauri/plugin/PluginManager.kt @@ -5,6 +5,7 @@ package app.tauri.plugin import android.app.PendingIntent +import android.content.res.Configuration import android.content.Context import android.content.Intent import android.webkit.WebView @@ -98,6 +99,30 @@ class PluginManager(val activity: AppCompatActivity) { } } + fun onRestart() { + for (plugin in plugins.values) { + plugin.instance.onRestart() + } + } + + fun onStop() { + for (plugin in plugins.values) { + plugin.instance.onStop() + } + } + + fun onDestroy() { + for (plugin in plugins.values) { + plugin.instance.onDestroy() + } + } + + fun onConfigurationChanged(newConfig: Configuration) { + for (plugin in plugins.values) { + plugin.instance.onConfigurationChanged(newConfig) + } + } + fun startActivityForResult(intent: Intent, callback: ActivityResultCallback) { startActivityForResultCallback = callback startActivityForResultLauncher.launch(intent) diff --git a/crates/tauri/mobile/ios-api/Sources/Tauri/Logger.swift b/crates/tauri/mobile/ios-api/Sources/Tauri/Logger.swift index 9fa6e3fe7..d055090dc 100644 --- a/crates/tauri/mobile/ios-api/Sources/Tauri/Logger.swift +++ b/crates/tauri/mobile/ios-api/Sources/Tauri/Logger.swift @@ -4,6 +4,86 @@ import os.log import UIKit +import Foundation + +class StdoutRedirector { + private var originalStdout: Int32 = -1 + private var originalStderr: Int32 = -1 + private var stdoutPipe: [Int32] = [-1, -1] + private var stderrPipe: [Int32] = [-1, -1] + private var stdoutReadSource: DispatchSourceRead? + private var stderrReadSource: DispatchSourceRead? + + func start() { + originalStdout = dup(STDOUT_FILENO) + originalStderr = dup(STDERR_FILENO) + + guard Darwin.pipe(&stdoutPipe) == 0, + Darwin.pipe(&stderrPipe) == 0 else { + Logger.error("Failed to create stdout/stderr pipes") + return + } + + dup2(stdoutPipe[1], STDOUT_FILENO) + dup2(stderrPipe[1], STDERR_FILENO) + close(stdoutPipe[1]) + close(stderrPipe[1]) + + stdoutReadSource = createReader( + readPipe: stdoutPipe[0], + writeToOriginal: originalStdout, + label: "stdout" + ) + + stderrReadSource = createReader( + readPipe: stderrPipe[0], + writeToOriginal: originalStderr, + label: "stderr" + ) + } + + private func createReader( + readPipe: Int32, + writeToOriginal: Int32, + label: String + ) -> DispatchSourceRead { + let source = DispatchSource.makeReadSource( + fileDescriptor: readPipe, + queue: .global(qos: .utility) + ) + + source.setEventHandler { + let bufferSize = 4096 + var buffer = [UInt8](repeating: 0, count: bufferSize) + let bytesRead = read(readPipe, &buffer, bufferSize) + + if bytesRead > 0 { + let output = String( + bytes: buffer[0.. +`core:app:allow-register-listener` + + + + +Enables the register_listener command without any pre-configured scope. + + + + + + + +`core:app:deny-register-listener` + + + + +Denies the register_listener command without any pre-configured scope. + + + + + + + `core:app:allow-remove-data-store` @@ -230,6 +258,32 @@ Denies the remove_data_store command without any pre-configured scope. +`core:app:allow-remove-listener` + + + + +Enables the remove_listener command without any pre-configured scope. + + + + + + + +`core:app:deny-remove-listener` + + + + +Denies the remove_listener command without any pre-configured scope. + + + + + + + `core:app:allow-set-app-theme` diff --git a/crates/tauri/scripts/bundle.global.js b/crates/tauri/scripts/bundle.global.js index 870ac2ec6..7f8eff34b 100644 --- a/crates/tauri/scripts/bundle.global.js +++ b/crates/tauri/scripts/bundle.global.js @@ -1 +1 @@ -var __TAURI_IIFE__=function(e){"use strict";function n(e,n,t,i){if("a"===t&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof n?e!==n||!i:!n.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?i:"a"===t?i.call(e):i?i.value:n.get(e)}function t(e,n,t,i,r){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof n?e!==n||!r:!n.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?r.call(e,t):r?r.value=t:n.set(e,t),t}var i,r,s,a,l;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";function u(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}class c{constructor(e){i.set(this,void 0),r.set(this,0),s.set(this,[]),a.set(this,void 0),t(this,i,e||(()=>{}),"f"),this.id=u(e=>{const l=e.index;if("end"in e)return void(l==n(this,r,"f")?this.cleanupCallback():t(this,a,l,"f"));const o=e.message;if(l==n(this,r,"f")){for(n(this,i,"f").call(this,o),t(this,r,n(this,r,"f")+1,"f");n(this,r,"f")in n(this,s,"f");){const e=n(this,s,"f")[n(this,r,"f")];n(this,i,"f").call(this,e),delete n(this,s,"f")[n(this,r,"f")],t(this,r,n(this,r,"f")+1,"f")}n(this,r,"f")===n(this,a,"f")&&this.cleanupCallback()}else n(this,s,"f")[l]=o})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(e){t(this,i,e,"f")}get onmessage(){return n(this,i,"f")}[(i=new WeakMap,r=new WeakMap,s=new WeakMap,a=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}class d{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return p(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function p(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}class h{get rid(){return n(this,l,"f")}constructor(e){l.set(this,void 0),t(this,l,e,"f")}async close(){return p("plugin:resources|close",{rid:this.rid})}}l=new WeakMap;var w=Object.freeze({__proto__:null,Channel:c,PluginListener:d,Resource:h,SERIALIZE_TO_IPC_FN:o,addPluginListener:async function(e,n,t){const i=new c(t);try{return p(`plugin:${e}|register_listener`,{event:n,handler:i}).then(()=>new d(e,n,i.id))}catch{return p(`plugin:${e}|registerListener`,{event:n,handler:i}).then(()=>new d(e,n,i.id))}},checkPermissions:async function(e){return p(`plugin:${e}|check_permissions`)},convertFileSrc:function(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)},invoke:p,isTauri:function(){return!!(globalThis||window).isTauri},requestPermissions:async function(e){return p(`plugin:${e}|request_permissions`)},transformCallback:u});class _ extends h{constructor(e){super(e)}static async new(e,n,t){return p("plugin:image|new",{rgba:y(e),width:n,height:t}).then(e=>new _(e))}static async fromBytes(e){return p("plugin:image|from_bytes",{bytes:y(e)}).then(e=>new _(e))}static async fromPath(e){return p("plugin:image|from_path",{path:e}).then(e=>new _(e))}async rgba(){return p("plugin:image|rgba",{rid:this.rid}).then(e=>new Uint8Array(e))}async size(){return p("plugin:image|size",{rid:this.rid})}}function y(e){return null==e?null:"string"==typeof e?e:e instanceof _?e.rid:e}var g,b=Object.freeze({__proto__:null,Image:_,transformImage:y});!function(e){e.Nsis="nsis",e.Msi="msi",e.Deb="deb",e.Rpm="rpm",e.AppImage="appimage",e.App="app"}(g||(g={}));var m=Object.freeze({__proto__:null,get BundleType(){return g},defaultWindowIcon:async function(){return p("plugin:app|default_window_icon").then(e=>e?new _(e):null)},fetchDataStoreIdentifiers:async function(){return p("plugin:app|fetch_data_store_identifiers")},getBundleType:async function(){return p("plugin:app|bundle_type")},getIdentifier:async function(){return p("plugin:app|identifier")},getName:async function(){return p("plugin:app|name")},getTauriVersion:async function(){return p("plugin:app|tauri_version")},getVersion:async function(){return p("plugin:app|version")},hide:async function(){return p("plugin:app|app_hide")},removeDataStore:async function(e){return p("plugin:app|remove_data_store",{uuid:e})},setDockVisibility:async function(e){return p("plugin:app|set_dock_visibility",{visible:e})},setTheme:async function(e){return p("plugin:app|set_app_theme",{theme:e})},show:async function(){return p("plugin:app|app_show")}});class f{constructor(...e){this.type="Logical",1===e.length?"Logical"in e[0]?(this.width=e[0].Logical.width,this.height=e[0].Logical.height):(this.width=e[0].width,this.height=e[0].height):(this.width=e[0],this.height=e[1])}toPhysical(e){return new v(this.width*e,this.height*e)}[o](){return{width:this.width,height:this.height}}toJSON(){return this[o]()}}class v{constructor(...e){this.type="Physical",1===e.length?"Physical"in e[0]?(this.width=e[0].Physical.width,this.height=e[0].Physical.height):(this.width=e[0].width,this.height=e[0].height):(this.width=e[0],this.height=e[1])}toLogical(e){return new f(this.width/e,this.height/e)}[o](){return{width:this.width,height:this.height}}toJSON(){return this[o]()}}class k{constructor(e){this.size=e}toLogical(e){return this.size instanceof f?this.size:this.size.toLogical(e)}toPhysical(e){return this.size instanceof v?this.size:this.size.toPhysical(e)}[o](){return{[`${this.size.type}`]:{width:this.size.width,height:this.size.height}}}toJSON(){return this[o]()}}class A{constructor(...e){this.type="Logical",1===e.length?"Logical"in e[0]?(this.x=e[0].Logical.x,this.y=e[0].Logical.y):(this.x=e[0].x,this.y=e[0].y):(this.x=e[0],this.y=e[1])}toPhysical(e){return new T(this.x*e,this.y*e)}[o](){return{x:this.x,y:this.y}}toJSON(){return this[o]()}}class T{constructor(...e){this.type="Physical",1===e.length?"Physical"in e[0]?(this.x=e[0].Physical.x,this.y=e[0].Physical.y):(this.x=e[0].x,this.y=e[0].y):(this.x=e[0],this.y=e[1])}toLogical(e){return new A(this.x/e,this.y/e)}[o](){return{x:this.x,y:this.y}}toJSON(){return this[o]()}}class I{constructor(e){this.position=e}toLogical(e){return this.position instanceof A?this.position:this.position.toLogical(e)}toPhysical(e){return this.position instanceof T?this.position:this.position.toPhysical(e)}[o](){return{[`${this.position.type}`]:{x:this.position.x,y:this.position.y}}}toJSON(){return this[o]()}}var E,R=Object.freeze({__proto__:null,LogicalPosition:A,LogicalSize:f,PhysicalPosition:T,PhysicalSize:v,Position:I,Size:k});async function D(e,n){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(e,n),await p("plugin:event|unlisten",{event:e,eventId:n})}async function S(e,n,t){var i;const r="string"==typeof(null==t?void 0:t.target)?{kind:"AnyLabel",label:t.target}:null!==(i=null==t?void 0:t.target)&&void 0!==i?i:{kind:"Any"};return p("plugin:event|listen",{event:e,target:r,handler:u(n)}).then(n=>async()=>D(e,n))}async function N(e,n,t){return S(e,t=>{D(e,t.id),n(t)},t)}async function L(e,n){await p("plugin:event|emit",{event:e,payload:n})}async function C(e,n,t){const i="string"==typeof e?{kind:"AnyLabel",label:e}:e;await p("plugin:event|emit_to",{target:i,event:n,payload:t})}!function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"}(E||(E={}));var x,P,z,W=Object.freeze({__proto__:null,get TauriEvent(){return E},emit:L,emitTo:C,listen:S,once:N});function O(e){var n;if("items"in e)e.items=null===(n=e.items)||void 0===n?void 0:n.map(e=>"rid"in e?e:O(e));else if("action"in e&&e.action){const n=new c;return n.onmessage=e.action,delete e.action,{...e,handler:n}}return e}async function U(e,n){const t=new c;if(n&&"object"==typeof n&&("action"in n&&n.action&&(t.onmessage=n.action,delete n.action),"item"in n&&n.item&&"object"==typeof n.item&&"About"in n.item&&n.item.About&&"object"==typeof n.item.About&&"icon"in n.item.About&&n.item.About.icon&&(n.item.About.icon=y(n.item.About.icon)),"icon"in n&&n.icon&&(n.icon=y(n.icon)),"items"in n&&n.items)){function i(e){var n;return"rid"in e?[e.rid,e.kind]:("item"in e&&"object"==typeof e.item&&(null===(n=e.item.About)||void 0===n?void 0:n.icon)&&(e.item.About.icon=y(e.item.About.icon)),"icon"in e&&e.icon&&(e.icon=y(e.icon)),"items"in e&&e.items&&(e.items=e.items.map(i)),O(e))}n.items=n.items.map(i)}return p("plugin:menu|new",{kind:e,options:n,handler:t})}class F extends h{get id(){return n(this,x,"f")}get kind(){return n(this,P,"f")}constructor(e,n,i){super(e),x.set(this,void 0),P.set(this,void 0),t(this,x,n,"f"),t(this,P,i,"f")}}x=new WeakMap,P=new WeakMap;class M extends F{constructor(e,n){super(e,n,"MenuItem")}static async new(e){return U("MenuItem",e).then(([e,n])=>new M(e,n))}async text(){return p("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return p("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return p("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return p("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return p("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}}class B extends F{constructor(e,n){super(e,n,"Check")}static async new(e){return U("Check",e).then(([e,n])=>new B(e,n))}async text(){return p("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return p("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return p("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return p("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return p("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async isChecked(){return p("plugin:menu|is_checked",{rid:this.rid})}async setChecked(e){return p("plugin:menu|set_checked",{rid:this.rid,checked:e})}}!function(e){e.Add="Add",e.Advanced="Advanced",e.Bluetooth="Bluetooth",e.Bookmarks="Bookmarks",e.Caution="Caution",e.ColorPanel="ColorPanel",e.ColumnView="ColumnView",e.Computer="Computer",e.EnterFullScreen="EnterFullScreen",e.Everyone="Everyone",e.ExitFullScreen="ExitFullScreen",e.FlowView="FlowView",e.Folder="Folder",e.FolderBurnable="FolderBurnable",e.FolderSmart="FolderSmart",e.FollowLinkFreestanding="FollowLinkFreestanding",e.FontPanel="FontPanel",e.GoLeft="GoLeft",e.GoRight="GoRight",e.Home="Home",e.IChatTheater="IChatTheater",e.IconView="IconView",e.Info="Info",e.InvalidDataFreestanding="InvalidDataFreestanding",e.LeftFacingTriangle="LeftFacingTriangle",e.ListView="ListView",e.LockLocked="LockLocked",e.LockUnlocked="LockUnlocked",e.MenuMixedState="MenuMixedState",e.MenuOnState="MenuOnState",e.MobileMe="MobileMe",e.MultipleDocuments="MultipleDocuments",e.Network="Network",e.Path="Path",e.PreferencesGeneral="PreferencesGeneral",e.QuickLook="QuickLook",e.RefreshFreestanding="RefreshFreestanding",e.Refresh="Refresh",e.Remove="Remove",e.RevealFreestanding="RevealFreestanding",e.RightFacingTriangle="RightFacingTriangle",e.Share="Share",e.Slideshow="Slideshow",e.SmartBadge="SmartBadge",e.StatusAvailable="StatusAvailable",e.StatusNone="StatusNone",e.StatusPartiallyAvailable="StatusPartiallyAvailable",e.StatusUnavailable="StatusUnavailable",e.StopProgressFreestanding="StopProgressFreestanding",e.StopProgress="StopProgress",e.TrashEmpty="TrashEmpty",e.TrashFull="TrashFull",e.User="User",e.UserAccounts="UserAccounts",e.UserGroup="UserGroup",e.UserGuest="UserGuest"}(z||(z={}));class V extends F{constructor(e,n){super(e,n,"Icon")}static async new(e){return U("Icon",e).then(([e,n])=>new V(e,n))}async text(){return p("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return p("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return p("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return p("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return p("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async setIcon(e){return p("plugin:menu|set_icon",{rid:this.rid,kind:this.kind,icon:y(e)})}}class G extends F{constructor(e,n){super(e,n,"Predefined")}static async new(e){return U("Predefined",e).then(([e,n])=>new G(e,n))}async text(){return p("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return p("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}}function j([e,n,t]){switch(t){case"Submenu":return new H(e,n);case"Predefined":return new G(e,n);case"Check":return new B(e,n);case"Icon":return new V(e,n);default:return new M(e,n)}}class H extends F{constructor(e,n){super(e,n,"Submenu")}static async new(e){return U("Submenu",e).then(([e,n])=>new H(e,n))}async text(){return p("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return p("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return p("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return p("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async append(e){return p("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async prepend(e){return p("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async insert(e,n){return p("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e),position:n})}async remove(e){return p("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return p("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(j)}async items(){return p("plugin:menu|items",{rid:this.rid,kind:this.kind}).then(e=>e.map(j))}async get(e){return p("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then(e=>e?j(e):null)}async popup(e,n){var t;return p("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:null!==(t=null==n?void 0:n.label)&&void 0!==t?t:null,at:e instanceof I?e:e?new I(e):null})}async setAsWindowsMenuForNSApp(){return p("plugin:menu|set_as_windows_menu_for_nsapp",{rid:this.rid})}async setAsHelpMenuForNSApp(){return p("plugin:menu|set_as_help_menu_for_nsapp",{rid:this.rid})}async setIcon(e){return p("plugin:menu|set_icon",{rid:this.rid,kind:this.kind,icon:y(e)})}}class $ extends F{constructor(e,n){super(e,n,"Menu")}static async new(e){return U("Menu",e).then(([e,n])=>new $(e,n))}static async default(){return p("plugin:menu|create_default").then(([e,n])=>new $(e,n))}async append(e){return p("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async prepend(e){return p("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async insert(e,n){return p("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e),position:n})}async remove(e){return p("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return p("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(j)}async items(){return p("plugin:menu|items",{rid:this.rid,kind:this.kind}).then(e=>e.map(j))}async get(e){return p("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then(e=>e?j(e):null)}async popup(e,n){var t;return p("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:null!==(t=null==n?void 0:n.label)&&void 0!==t?t:null,at:e instanceof I?e:e?new I(e):null})}async setAsAppMenu(){return p("plugin:menu|set_as_app_menu",{rid:this.rid}).then(e=>e?new $(e[0],e[1]):null)}async setAsWindowMenu(e){var n;return p("plugin:menu|set_as_window_menu",{rid:this.rid,window:null!==(n=null==e?void 0:e.label)&&void 0!==n?n:null}).then(e=>e?new $(e[0],e[1]):null)}}var q=Object.freeze({__proto__:null,CheckMenuItem:B,IconMenuItem:V,Menu:$,MenuItem:M,get NativeIcon(){return z},PredefinedMenuItem:G,Submenu:H,itemFromKind:j});function J(){var e,n;window.__TAURI_INTERNALS__=null!==(e=window.__TAURI_INTERNALS__)&&void 0!==e?e:{},window.__TAURI_EVENT_PLUGIN_INTERNALS__=null!==(n=window.__TAURI_EVENT_PLUGIN_INTERNALS__)&&void 0!==n?n:{}}var Q,Z=Object.freeze({__proto__:null,clearMocks:function(){"object"==typeof window.__TAURI_INTERNALS__&&(delete window.__TAURI_INTERNALS__.invoke,delete window.__TAURI_INTERNALS__.transformCallback,delete window.__TAURI_INTERNALS__.unregisterCallback,delete window.__TAURI_INTERNALS__.runCallback,delete window.__TAURI_INTERNALS__.callbacks,delete window.__TAURI_INTERNALS__.convertFileSrc,delete window.__TAURI_INTERNALS__.metadata,"object"==typeof window.__TAURI_EVENT_PLUGIN_INTERNALS__&&delete window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener)},mockConvertFileSrc:function(e){J(),window.__TAURI_INTERNALS__.convertFileSrc=function(n,t="asset"){const i=encodeURIComponent(n);return"windows"===e?`http://${t}.localhost/${i}`:`${t}://localhost/${i}`}},mockIPC:function(e,n){function t(e,n){switch(e){case"plugin:event|listen":return function(e){i.has(e.event)||i.set(e.event,[]);return i.get(e.event).push(e.handler),e.handler}(n);case"plugin:event|emit":return function(e){const n=i.get(e.event)||[];for(const t of n)a(t,e);return null}(n);case"plugin:event|unlisten":return function(e){const n=i.get(e.event);if(n){const t=n.indexOf(e.id);-1!==t&&n.splice(t,1)}}(n)}}J();const i=new Map,r=new Map;function s(e){r.delete(e)}function a(e,n){const t=r.get(e);t?t(n):console.warn(`[TAURI] Couldn't find callback id ${e}. This might happen when the app is reloaded while Rust is running an asynchronous operation.`)}window.__TAURI_INTERNALS__.invoke=async function(i,r,s){return(null==n?void 0:n.shouldMockEvents)&&function(e){return e.startsWith("plugin:event|")}(i)?t(i,r):e(i,r)},window.__TAURI_INTERNALS__.transformCallback=function(e,n=!1){const t=window.crypto.getRandomValues(new Uint32Array(1))[0];return r.set(t,i=>(n&&s(t),e&&e(i))),t},window.__TAURI_INTERNALS__.unregisterCallback=s,window.__TAURI_INTERNALS__.runCallback=a,window.__TAURI_INTERNALS__.callbacks=r,window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener=function(e,n){s(n)}},mockWindows:function(e,...n){J(),window.__TAURI_INTERNALS__.metadata={currentWindow:{label:e},currentWebview:{windowLabel:e,label:e}}}});!function(e){e[e.Audio=1]="Audio",e[e.Cache=2]="Cache",e[e.Config=3]="Config",e[e.Data=4]="Data",e[e.LocalData=5]="LocalData",e[e.Document=6]="Document",e[e.Download=7]="Download",e[e.Picture=8]="Picture",e[e.Public=9]="Public",e[e.Video=10]="Video",e[e.Resource=11]="Resource",e[e.Temp=12]="Temp",e[e.AppConfig=13]="AppConfig",e[e.AppData=14]="AppData",e[e.AppLocalData=15]="AppLocalData",e[e.AppCache=16]="AppCache",e[e.AppLog=17]="AppLog",e[e.Desktop=18]="Desktop",e[e.Executable=19]="Executable",e[e.Font=20]="Font",e[e.Home=21]="Home",e[e.Runtime=22]="Runtime",e[e.Template=23]="Template"}(Q||(Q={}));var K=Object.freeze({__proto__:null,get BaseDirectory(){return Q},appCacheDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.AppCache})},appConfigDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.AppConfig})},appDataDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.AppData})},appLocalDataDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.AppLocalData})},appLogDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.AppLog})},audioDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Audio})},basename:async function(e,n){return p("plugin:path|basename",{path:e,ext:n})},cacheDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Cache})},configDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Config})},dataDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Data})},delimiter:function(){return window.__TAURI_INTERNALS__.plugins.path.delimiter},desktopDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Desktop})},dirname:async function(e){return p("plugin:path|dirname",{path:e})},documentDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Document})},downloadDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Download})},executableDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Executable})},extname:async function(e){return p("plugin:path|extname",{path:e})},fontDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Font})},homeDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Home})},isAbsolute:async function(e){return p("plugin:path|is_absolute",{path:e})},join:async function(...e){return p("plugin:path|join",{paths:e})},localDataDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.LocalData})},normalize:async function(e){return p("plugin:path|normalize",{path:e})},pictureDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Picture})},publicDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Public})},resolve:async function(...e){return p("plugin:path|resolve",{paths:e})},resolveResource:async function(e){return p("plugin:path|resolve_directory",{directory:Q.Resource,path:e})},resourceDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Resource})},runtimeDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Runtime})},sep:function(){return window.__TAURI_INTERNALS__.plugins.path.sep},tempDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Temp})},templateDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Template})},videoDir:async function(){return p("plugin:path|resolve_directory",{directory:Q.Video})}});class Y extends h{constructor(e,n){super(e),this.id=n}static async getById(e){return p("plugin:tray|get_by_id",{id:e}).then(n=>n?new Y(n,e):null)}static async removeById(e){return p("plugin:tray|remove_by_id",{id:e})}static async new(e){(null==e?void 0:e.menu)&&(e.menu=[e.menu.rid,e.menu.kind]),(null==e?void 0:e.icon)&&(e.icon=y(e.icon));const n=new c;if(null==e?void 0:e.action){const t=e.action;n.onmessage=e=>t(function(e){const n=e;return n.position=new T(e.position),n.rect.position=new T(e.rect.position),n.rect.size=new v(e.rect.size),n}(e)),delete e.action}return p("plugin:tray|new",{options:null!=e?e:{},handler:n}).then(([e,n])=>new Y(e,n))}async setIcon(e){let n=null;return e&&(n=y(e)),p("plugin:tray|set_icon",{rid:this.rid,icon:n})}async setMenu(e){return e&&(e=[e.rid,e.kind]),p("plugin:tray|set_menu",{rid:this.rid,menu:e})}async setTooltip(e){return p("plugin:tray|set_tooltip",{rid:this.rid,tooltip:e})}async setTitle(e){return p("plugin:tray|set_title",{rid:this.rid,title:e})}async setVisible(e){return p("plugin:tray|set_visible",{rid:this.rid,visible:e})}async setTempDirPath(e){return p("plugin:tray|set_temp_dir_path",{rid:this.rid,path:e})}async setIconAsTemplate(e){return p("plugin:tray|set_icon_as_template",{rid:this.rid,asTemplate:e})}async setMenuOnLeftClick(e){return p("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}async setShowMenuOnLeftClick(e){return p("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}}var X,ee,ne=Object.freeze({__proto__:null,TrayIcon:Y});!function(e){e[e.Critical=1]="Critical",e[e.Informational=2]="Informational"}(X||(X={}));class te{constructor(e){this._preventDefault=!1,this.event=e.event,this.id=e.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}}function ie(){return new ae(window.__TAURI_INTERNALS__.metadata.currentWindow.label,{skip:!0})}async function re(){return p("plugin:window|get_all_windows").then(e=>e.map(e=>new ae(e,{skip:!0})))}!function(e){e.None="none",e.Normal="normal",e.Indeterminate="indeterminate",e.Paused="paused",e.Error="error"}(ee||(ee={}));const se=["tauri://created","tauri://error"];class ae{constructor(e,n={}){var t;this.label=e,this.listeners=Object.create(null),(null==n?void 0:n.skip)||p("plugin:window|create",{options:{...n,parent:"string"==typeof n.parent?n.parent:null===(t=n.parent)||void 0===t?void 0:t.label,label:e}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;return null!==(n=(await re()).find(n=>n.label===e))&&void 0!==n?n:null}static getCurrent(){return ie()}static async getAll(){return re()}static async getFocusedWindow(){for(const e of await re())if(await e.isFocused())return e;return null}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:S(e,n,{target:{kind:"Window",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"Window",label:this.label}})}async emit(e,n){if(!se.includes(e))return L(e,n);for(const t of this.listeners[e]||[])t({event:e,id:-1,payload:n})}async emitTo(e,n,t){if(!se.includes(n))return C(e,n,t);for(const e of this.listeners[n]||[])e({event:n,id:-1,payload:t})}_handleTauriEvent(e,n){return!!se.includes(e)&&(e in this.listeners?this.listeners[e].push(n):this.listeners[e]=[n],!0)}async scaleFactor(){return p("plugin:window|scale_factor",{label:this.label})}async innerPosition(){return p("plugin:window|inner_position",{label:this.label}).then(e=>new T(e))}async outerPosition(){return p("plugin:window|outer_position",{label:this.label}).then(e=>new T(e))}async innerSize(){return p("plugin:window|inner_size",{label:this.label}).then(e=>new v(e))}async outerSize(){return p("plugin:window|outer_size",{label:this.label}).then(e=>new v(e))}async isFullscreen(){return p("plugin:window|is_fullscreen",{label:this.label})}async isMinimized(){return p("plugin:window|is_minimized",{label:this.label})}async isMaximized(){return p("plugin:window|is_maximized",{label:this.label})}async isFocused(){return p("plugin:window|is_focused",{label:this.label})}async isDecorated(){return p("plugin:window|is_decorated",{label:this.label})}async isResizable(){return p("plugin:window|is_resizable",{label:this.label})}async isMaximizable(){return p("plugin:window|is_maximizable",{label:this.label})}async isMinimizable(){return p("plugin:window|is_minimizable",{label:this.label})}async isClosable(){return p("plugin:window|is_closable",{label:this.label})}async isVisible(){return p("plugin:window|is_visible",{label:this.label})}async title(){return p("plugin:window|title",{label:this.label})}async theme(){return p("plugin:window|theme",{label:this.label})}async isAlwaysOnTop(){return p("plugin:window|is_always_on_top",{label:this.label})}async center(){return p("plugin:window|center",{label:this.label})}async requestUserAttention(e){let n=null;return e&&(n=e===X.Critical?{type:"Critical"}:{type:"Informational"}),p("plugin:window|request_user_attention",{label:this.label,value:n})}async setResizable(e){return p("plugin:window|set_resizable",{label:this.label,value:e})}async setEnabled(e){return p("plugin:window|set_enabled",{label:this.label,value:e})}async isEnabled(){return p("plugin:window|is_enabled",{label:this.label})}async setMaximizable(e){return p("plugin:window|set_maximizable",{label:this.label,value:e})}async setMinimizable(e){return p("plugin:window|set_minimizable",{label:this.label,value:e})}async setClosable(e){return p("plugin:window|set_closable",{label:this.label,value:e})}async setTitle(e){return p("plugin:window|set_title",{label:this.label,value:e})}async maximize(){return p("plugin:window|maximize",{label:this.label})}async unmaximize(){return p("plugin:window|unmaximize",{label:this.label})}async toggleMaximize(){return p("plugin:window|toggle_maximize",{label:this.label})}async minimize(){return p("plugin:window|minimize",{label:this.label})}async unminimize(){return p("plugin:window|unminimize",{label:this.label})}async show(){return p("plugin:window|show",{label:this.label})}async hide(){return p("plugin:window|hide",{label:this.label})}async close(){return p("plugin:window|close",{label:this.label})}async destroy(){return p("plugin:window|destroy",{label:this.label})}async setDecorations(e){return p("plugin:window|set_decorations",{label:this.label,value:e})}async setShadow(e){return p("plugin:window|set_shadow",{label:this.label,value:e})}async setEffects(e){return p("plugin:window|set_effects",{label:this.label,value:e})}async clearEffects(){return p("plugin:window|set_effects",{label:this.label,value:null})}async setAlwaysOnTop(e){return p("plugin:window|set_always_on_top",{label:this.label,value:e})}async setAlwaysOnBottom(e){return p("plugin:window|set_always_on_bottom",{label:this.label,value:e})}async setContentProtected(e){return p("plugin:window|set_content_protected",{label:this.label,value:e})}async setSize(e){return p("plugin:window|set_size",{label:this.label,value:e instanceof k?e:new k(e)})}async setMinSize(e){return p("plugin:window|set_min_size",{label:this.label,value:e instanceof k?e:e?new k(e):null})}async setMaxSize(e){return p("plugin:window|set_max_size",{label:this.label,value:e instanceof k?e:e?new k(e):null})}async setSizeConstraints(e){function n(e){return e?{Logical:e}:null}return p("plugin:window|set_size_constraints",{label:this.label,value:{minWidth:n(null==e?void 0:e.minWidth),minHeight:n(null==e?void 0:e.minHeight),maxWidth:n(null==e?void 0:e.maxWidth),maxHeight:n(null==e?void 0:e.maxHeight)}})}async setPosition(e){return p("plugin:window|set_position",{label:this.label,value:e instanceof I?e:new I(e)})}async setFullscreen(e){return p("plugin:window|set_fullscreen",{label:this.label,value:e})}async setSimpleFullscreen(e){return p("plugin:window|set_simple_fullscreen",{label:this.label,value:e})}async setFocus(){return p("plugin:window|set_focus",{label:this.label})}async setFocusable(e){return p("plugin:window|set_focusable",{label:this.label,value:e})}async setIcon(e){return p("plugin:window|set_icon",{label:this.label,value:y(e)})}async setSkipTaskbar(e){return p("plugin:window|set_skip_taskbar",{label:this.label,value:e})}async setCursorGrab(e){return p("plugin:window|set_cursor_grab",{label:this.label,value:e})}async setCursorVisible(e){return p("plugin:window|set_cursor_visible",{label:this.label,value:e})}async setCursorIcon(e){return p("plugin:window|set_cursor_icon",{label:this.label,value:e})}async setBackgroundColor(e){return p("plugin:window|set_background_color",{color:e})}async setCursorPosition(e){return p("plugin:window|set_cursor_position",{label:this.label,value:e instanceof I?e:new I(e)})}async setIgnoreCursorEvents(e){return p("plugin:window|set_ignore_cursor_events",{label:this.label,value:e})}async startDragging(){return p("plugin:window|start_dragging",{label:this.label})}async startResizeDragging(e){return p("plugin:window|start_resize_dragging",{label:this.label,value:e})}async setBadgeCount(e){return p("plugin:window|set_badge_count",{label:this.label,value:e})}async setBadgeLabel(e){return p("plugin:window|set_badge_label",{label:this.label,value:e})}async setOverlayIcon(e){return p("plugin:window|set_overlay_icon",{label:this.label,value:e?y(e):void 0})}async setProgressBar(e){return p("plugin:window|set_progress_bar",{label:this.label,value:e})}async setVisibleOnAllWorkspaces(e){return p("plugin:window|set_visible_on_all_workspaces",{label:this.label,value:e})}async setTitleBarStyle(e){return p("plugin:window|set_title_bar_style",{label:this.label,value:e})}async setTheme(e){return p("plugin:window|set_theme",{label:this.label,value:e})}async onResized(e){return this.listen(E.WINDOW_RESIZED,n=>{n.payload=new v(n.payload),e(n)})}async onMoved(e){return this.listen(E.WINDOW_MOVED,n=>{n.payload=new T(n.payload),e(n)})}async onCloseRequested(e){return this.listen(E.WINDOW_CLOSE_REQUESTED,async n=>{const t=new te(n);await e(t),t.isPreventDefault()||await this.destroy()})}async onDragDropEvent(e){const n=await this.listen(E.DRAG_ENTER,n=>{e({...n,payload:{type:"enter",paths:n.payload.paths,position:new T(n.payload.position)}})}),t=await this.listen(E.DRAG_OVER,n=>{e({...n,payload:{type:"over",position:new T(n.payload.position)}})}),i=await this.listen(E.DRAG_DROP,n=>{e({...n,payload:{type:"drop",paths:n.payload.paths,position:new T(n.payload.position)}})}),r=await this.listen(E.DRAG_LEAVE,n=>{e({...n,payload:{type:"leave"}})});return()=>{n(),i(),t(),r()}}async onFocusChanged(e){const n=await this.listen(E.WINDOW_FOCUS,n=>{e({...n,payload:!0})}),t=await this.listen(E.WINDOW_BLUR,n=>{e({...n,payload:!1})});return()=>{n(),t()}}async onScaleChanged(e){return this.listen(E.WINDOW_SCALE_FACTOR_CHANGED,e)}async onThemeChanged(e){return this.listen(E.WINDOW_THEME_CHANGED,e)}}var le,oe,ue,ce;function de(e){return null===e?null:{name:e.name,scaleFactor:e.scaleFactor,position:new T(e.position),size:new v(e.size),workArea:{position:new T(e.workArea.position),size:new v(e.workArea.size)}}}!function(e){e.Disabled="disabled",e.Throttle="throttle",e.Suspend="suspend"}(le||(le={})),function(e){e.Default="default",e.FluentOverlay="fluentOverlay"}(oe||(oe={})),function(e){e.AppearanceBased="appearanceBased",e.Light="light",e.Dark="dark",e.MediumLight="mediumLight",e.UltraDark="ultraDark",e.Titlebar="titlebar",e.Selection="selection",e.Menu="menu",e.Popover="popover",e.Sidebar="sidebar",e.HeaderView="headerView",e.Sheet="sheet",e.WindowBackground="windowBackground",e.HudWindow="hudWindow",e.FullScreenUI="fullScreenUI",e.Tooltip="tooltip",e.ContentBackground="contentBackground",e.UnderWindowBackground="underWindowBackground",e.UnderPageBackground="underPageBackground",e.Mica="mica",e.Blur="blur",e.Acrylic="acrylic",e.Tabbed="tabbed",e.TabbedDark="tabbedDark",e.TabbedLight="tabbedLight"}(ue||(ue={})),function(e){e.FollowsWindowActiveState="followsWindowActiveState",e.Active="active",e.Inactive="inactive"}(ce||(ce={}));var pe=Object.freeze({__proto__:null,CloseRequestedEvent:te,get Effect(){return ue},get EffectState(){return ce},LogicalPosition:A,LogicalSize:f,PhysicalPosition:T,PhysicalSize:v,get ProgressBarStatus(){return ee},get UserAttentionType(){return X},Window:ae,availableMonitors:async function(){return p("plugin:window|available_monitors").then(e=>e.map(de))},currentMonitor:async function(){return p("plugin:window|current_monitor").then(de)},cursorPosition:async function(){return p("plugin:window|cursor_position").then(e=>new T(e))},getAllWindows:re,getCurrentWindow:ie,monitorFromPoint:async function(e,n){return p("plugin:window|monitor_from_point",{x:e,y:n}).then(de)},primaryMonitor:async function(){return p("plugin:window|primary_monitor").then(de)}});function he(){return new ye(ie(),window.__TAURI_INTERNALS__.metadata.currentWebview.label,{skip:!0})}async function we(){return p("plugin:webview|get_all_webviews").then(e=>e.map(e=>new ye(new ae(e.windowLabel,{skip:!0}),e.label,{skip:!0})))}const _e=["tauri://created","tauri://error"];class ye{constructor(e,n,t){this.window=e,this.label=n,this.listeners=Object.create(null),(null==t?void 0:t.skip)||p("plugin:webview|create_webview",{windowLabel:e.label,options:{...t,label:n}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;return null!==(n=(await we()).find(n=>n.label===e))&&void 0!==n?n:null}static getCurrent(){return he()}static async getAll(){return we()}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:S(e,n,{target:{kind:"Webview",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"Webview",label:this.label}})}async emit(e,n){if(!_e.includes(e))return L(e,n);for(const t of this.listeners[e]||[])t({event:e,id:-1,payload:n})}async emitTo(e,n,t){if(!_e.includes(n))return C(e,n,t);for(const e of this.listeners[n]||[])e({event:n,id:-1,payload:t})}_handleTauriEvent(e,n){return!!_e.includes(e)&&(e in this.listeners?this.listeners[e].push(n):this.listeners[e]=[n],!0)}async position(){return p("plugin:webview|webview_position",{label:this.label}).then(e=>new T(e))}async size(){return p("plugin:webview|webview_size",{label:this.label}).then(e=>new v(e))}async close(){return p("plugin:webview|webview_close",{label:this.label})}async setSize(e){return p("plugin:webview|set_webview_size",{label:this.label,value:e instanceof k?e:new k(e)})}async setPosition(e){return p("plugin:webview|set_webview_position",{label:this.label,value:e instanceof I?e:new I(e)})}async setFocus(){return p("plugin:webview|set_webview_focus",{label:this.label})}async setAutoResize(e){return p("plugin:webview|set_webview_auto_resize",{label:this.label,value:e})}async hide(){return p("plugin:webview|webview_hide",{label:this.label})}async show(){return p("plugin:webview|webview_show",{label:this.label})}async setZoom(e){return p("plugin:webview|set_webview_zoom",{label:this.label,value:e})}async reparent(e){return p("plugin:webview|reparent",{label:this.label,window:"string"==typeof e?e:e.label})}async clearAllBrowsingData(){return p("plugin:webview|clear_all_browsing_data")}async setBackgroundColor(e){return p("plugin:webview|set_webview_background_color",{color:e})}async onDragDropEvent(e){const n=await this.listen(E.DRAG_ENTER,n=>{e({...n,payload:{type:"enter",paths:n.payload.paths,position:new T(n.payload.position)}})}),t=await this.listen(E.DRAG_OVER,n=>{e({...n,payload:{type:"over",position:new T(n.payload.position)}})}),i=await this.listen(E.DRAG_DROP,n=>{e({...n,payload:{type:"drop",paths:n.payload.paths,position:new T(n.payload.position)}})}),r=await this.listen(E.DRAG_LEAVE,n=>{e({...n,payload:{type:"leave"}})});return()=>{n(),i(),t(),r()}}}var ge,be,me=Object.freeze({__proto__:null,Webview:ye,getAllWebviews:we,getCurrentWebview:he});function fe(){const e=he();return new ke(e.label,{skip:!0})}async function ve(){return p("plugin:window|get_all_windows").then(e=>e.map(e=>new ke(e,{skip:!0})))}class ke{constructor(e,n={}){var t;this.label=e,this.listeners=Object.create(null),(null==n?void 0:n.skip)||p("plugin:webview|create_webview_window",{options:{...n,parent:"string"==typeof n.parent?n.parent:null===(t=n.parent)||void 0===t?void 0:t.label,label:e}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;const t=null!==(n=(await ve()).find(n=>n.label===e))&&void 0!==n?n:null;return t?new ke(t.label,{skip:!0}):null}static getCurrent(){return fe()}static async getAll(){return ve()}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:S(e,n,{target:{kind:"WebviewWindow",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"WebviewWindow",label:this.label}})}async setBackgroundColor(e){return p("plugin:window|set_background_color",{color:e}).then(()=>p("plugin:webview|set_webview_background_color",{color:e}))}}ge=ke,be=[ae,ye],(Array.isArray(be)?be:[be]).forEach(e=>{Object.getOwnPropertyNames(e.prototype).forEach(n=>{var t;"object"==typeof ge.prototype&&ge.prototype&&n in ge.prototype||Object.defineProperty(ge.prototype,n,null!==(t=Object.getOwnPropertyDescriptor(e.prototype,n))&&void 0!==t?t:Object.create(null))})});var Ae=Object.freeze({__proto__:null,WebviewWindow:ke,getAllWebviewWindows:ve,getCurrentWebviewWindow:fe});return e.app=m,e.core=w,e.dpi=R,e.event=W,e.image=b,e.menu=q,e.mocks=Z,e.path=K,e.tray=ne,e.webview=me,e.webviewWindow=Ae,e.window=pe,e}({});window.__TAURI__=__TAURI_IIFE__; +var __TAURI_IIFE__=function(e){"use strict";function n(e,n,t,i){if("a"===t&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof n?e!==n||!i:!n.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?i:"a"===t?i.call(e):i?i.value:n.get(e)}function t(e,n,t,i,r){if("m"===i)throw new TypeError("Private method is not writable");if("a"===i&&!r)throw new TypeError("Private accessor was defined without a setter");if("function"==typeof n?e!==n||!r:!n.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return"a"===i?r.call(e,t):r?r.value=t:n.set(e,t),t}var i,r,s,a,l;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";function u(e,n=!1){return window.__TAURI_INTERNALS__.transformCallback(e,n)}class c{constructor(e){i.set(this,void 0),r.set(this,0),s.set(this,[]),a.set(this,void 0),t(this,i,e||(()=>{}),"f"),this.id=u(e=>{const l=e.index;if("end"in e)return void(l==n(this,r,"f")?this.cleanupCallback():t(this,a,l,"f"));const o=e.message;if(l==n(this,r,"f")){for(n(this,i,"f").call(this,o),t(this,r,n(this,r,"f")+1,"f");n(this,r,"f")in n(this,s,"f");){const e=n(this,s,"f")[n(this,r,"f")];n(this,i,"f").call(this,e),delete n(this,s,"f")[n(this,r,"f")],t(this,r,n(this,r,"f")+1,"f")}n(this,r,"f")===n(this,a,"f")&&this.cleanupCallback()}else n(this,s,"f")[l]=o})}cleanupCallback(){window.__TAURI_INTERNALS__.unregisterCallback(this.id)}set onmessage(e){t(this,i,e,"f")}get onmessage(){return n(this,i,"f")}[(i=new WeakMap,r=new WeakMap,s=new WeakMap,a=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}class d{constructor(e,n,t){this.plugin=e,this.event=n,this.channelId=t}async unregister(){return h(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function p(e,n,t){const i=new c(t);try{return await h(`plugin:${e}|register_listener`,{event:n,handler:i}),new d(e,n,i.id)}catch{return await h(`plugin:${e}|registerListener`,{event:n,handler:i}),new d(e,n,i.id)}}async function h(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}class w{get rid(){return n(this,l,"f")}constructor(e){l.set(this,void 0),t(this,l,e,"f")}async close(){return h("plugin:resources|close",{rid:this.rid})}}l=new WeakMap;var _=Object.freeze({__proto__:null,Channel:c,PluginListener:d,Resource:w,SERIALIZE_TO_IPC_FN:o,addPluginListener:p,checkPermissions:async function(e){return h(`plugin:${e}|check_permissions`)},convertFileSrc:function(e,n="asset"){return window.__TAURI_INTERNALS__.convertFileSrc(e,n)},invoke:h,isTauri:function(){return!!(globalThis||window).isTauri},requestPermissions:async function(e){return h(`plugin:${e}|request_permissions`)},transformCallback:u});class y extends w{constructor(e){super(e)}static async new(e,n,t){return h("plugin:image|new",{rgba:g(e),width:n,height:t}).then(e=>new y(e))}static async fromBytes(e){return h("plugin:image|from_bytes",{bytes:g(e)}).then(e=>new y(e))}static async fromPath(e){return h("plugin:image|from_path",{path:e}).then(e=>new y(e))}async rgba(){return h("plugin:image|rgba",{rid:this.rid}).then(e=>new Uint8Array(e))}async size(){return h("plugin:image|size",{rid:this.rid})}}function g(e){return null==e?null:"string"==typeof e?e:e instanceof y?e.rid:e}var b,m=Object.freeze({__proto__:null,Image:y,transformImage:g});!function(e){e.Nsis="nsis",e.Msi="msi",e.Deb="deb",e.Rpm="rpm",e.AppImage="appimage",e.App="app"}(b||(b={}));var f=Object.freeze({__proto__:null,get BundleType(){return b},defaultWindowIcon:async function(){return h("plugin:app|default_window_icon").then(e=>e?new y(e):null)},fetchDataStoreIdentifiers:async function(){return h("plugin:app|fetch_data_store_identifiers")},getBundleType:async function(){return h("plugin:app|bundle_type")},getIdentifier:async function(){return h("plugin:app|identifier")},getName:async function(){return h("plugin:app|name")},getTauriVersion:async function(){return h("plugin:app|tauri_version")},getVersion:async function(){return h("plugin:app|version")},hide:async function(){return h("plugin:app|app_hide")},onBackButtonPress:async function(e){return p("app","back-button",e)},removeDataStore:async function(e){return h("plugin:app|remove_data_store",{uuid:e})},setDockVisibility:async function(e){return h("plugin:app|set_dock_visibility",{visible:e})},setTheme:async function(e){return h("plugin:app|set_app_theme",{theme:e})},show:async function(){return h("plugin:app|app_show")}});class v{constructor(...e){this.type="Logical",1===e.length?"Logical"in e[0]?(this.width=e[0].Logical.width,this.height=e[0].Logical.height):(this.width=e[0].width,this.height=e[0].height):(this.width=e[0],this.height=e[1])}toPhysical(e){return new k(this.width*e,this.height*e)}[o](){return{width:this.width,height:this.height}}toJSON(){return this[o]()}}class k{constructor(...e){this.type="Physical",1===e.length?"Physical"in e[0]?(this.width=e[0].Physical.width,this.height=e[0].Physical.height):(this.width=e[0].width,this.height=e[0].height):(this.width=e[0],this.height=e[1])}toLogical(e){return new v(this.width/e,this.height/e)}[o](){return{width:this.width,height:this.height}}toJSON(){return this[o]()}}class A{constructor(e){this.size=e}toLogical(e){return this.size instanceof v?this.size:this.size.toLogical(e)}toPhysical(e){return this.size instanceof k?this.size:this.size.toPhysical(e)}[o](){return{[`${this.size.type}`]:{width:this.size.width,height:this.size.height}}}toJSON(){return this[o]()}}class T{constructor(...e){this.type="Logical",1===e.length?"Logical"in e[0]?(this.x=e[0].Logical.x,this.y=e[0].Logical.y):(this.x=e[0].x,this.y=e[0].y):(this.x=e[0],this.y=e[1])}toPhysical(e){return new I(this.x*e,this.y*e)}[o](){return{x:this.x,y:this.y}}toJSON(){return this[o]()}}class I{constructor(...e){this.type="Physical",1===e.length?"Physical"in e[0]?(this.x=e[0].Physical.x,this.y=e[0].Physical.y):(this.x=e[0].x,this.y=e[0].y):(this.x=e[0],this.y=e[1])}toLogical(e){return new T(this.x/e,this.y/e)}[o](){return{x:this.x,y:this.y}}toJSON(){return this[o]()}}class E{constructor(e){this.position=e}toLogical(e){return this.position instanceof T?this.position:this.position.toLogical(e)}toPhysical(e){return this.position instanceof I?this.position:this.position.toPhysical(e)}[o](){return{[`${this.position.type}`]:{x:this.position.x,y:this.position.y}}}toJSON(){return this[o]()}}var R,D=Object.freeze({__proto__:null,LogicalPosition:T,LogicalSize:v,PhysicalPosition:I,PhysicalSize:k,Position:E,Size:A});async function S(e,n){window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener(e,n),await h("plugin:event|unlisten",{event:e,eventId:n})}async function N(e,n,t){var i;const r="string"==typeof(null==t?void 0:t.target)?{kind:"AnyLabel",label:t.target}:null!==(i=null==t?void 0:t.target)&&void 0!==i?i:{kind:"Any"};return h("plugin:event|listen",{event:e,target:r,handler:u(n)}).then(n=>async()=>S(e,n))}async function L(e,n,t){return N(e,t=>{S(e,t.id),n(t)},t)}async function C(e,n){await h("plugin:event|emit",{event:e,payload:n})}async function x(e,n,t){const i="string"==typeof e?{kind:"AnyLabel",label:e}:e;await h("plugin:event|emit_to",{target:i,event:n,payload:t})}!function(e){e.WINDOW_RESIZED="tauri://resize",e.WINDOW_MOVED="tauri://move",e.WINDOW_CLOSE_REQUESTED="tauri://close-requested",e.WINDOW_DESTROYED="tauri://destroyed",e.WINDOW_FOCUS="tauri://focus",e.WINDOW_BLUR="tauri://blur",e.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",e.WINDOW_THEME_CHANGED="tauri://theme-changed",e.WINDOW_CREATED="tauri://window-created",e.WEBVIEW_CREATED="tauri://webview-created",e.DRAG_ENTER="tauri://drag-enter",e.DRAG_OVER="tauri://drag-over",e.DRAG_DROP="tauri://drag-drop",e.DRAG_LEAVE="tauri://drag-leave"}(R||(R={}));var P,z,W,O=Object.freeze({__proto__:null,get TauriEvent(){return R},emit:C,emitTo:x,listen:N,once:L});function U(e){var n;if("items"in e)e.items=null===(n=e.items)||void 0===n?void 0:n.map(e=>"rid"in e?e:U(e));else if("action"in e&&e.action){const n=new c;return n.onmessage=e.action,delete e.action,{...e,handler:n}}return e}async function F(e,n){const t=new c;if(n&&"object"==typeof n&&("action"in n&&n.action&&(t.onmessage=n.action,delete n.action),"item"in n&&n.item&&"object"==typeof n.item&&"About"in n.item&&n.item.About&&"object"==typeof n.item.About&&"icon"in n.item.About&&n.item.About.icon&&(n.item.About.icon=g(n.item.About.icon)),"icon"in n&&n.icon&&(n.icon=g(n.icon)),"items"in n&&n.items)){function i(e){var n;return"rid"in e?[e.rid,e.kind]:("item"in e&&"object"==typeof e.item&&(null===(n=e.item.About)||void 0===n?void 0:n.icon)&&(e.item.About.icon=g(e.item.About.icon)),"icon"in e&&e.icon&&(e.icon=g(e.icon)),"items"in e&&e.items&&(e.items=e.items.map(i)),U(e))}n.items=n.items.map(i)}return h("plugin:menu|new",{kind:e,options:n,handler:t})}class M extends w{get id(){return n(this,P,"f")}get kind(){return n(this,z,"f")}constructor(e,n,i){super(e),P.set(this,void 0),z.set(this,void 0),t(this,P,n,"f"),t(this,z,i,"f")}}P=new WeakMap,z=new WeakMap;class B extends M{constructor(e,n){super(e,n,"MenuItem")}static async new(e){return F("MenuItem",e).then(([e,n])=>new B(e,n))}async text(){return h("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return h("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return h("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return h("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return h("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}}class V extends M{constructor(e,n){super(e,n,"Check")}static async new(e){return F("Check",e).then(([e,n])=>new V(e,n))}async text(){return h("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return h("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return h("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return h("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return h("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async isChecked(){return h("plugin:menu|is_checked",{rid:this.rid})}async setChecked(e){return h("plugin:menu|set_checked",{rid:this.rid,checked:e})}}!function(e){e.Add="Add",e.Advanced="Advanced",e.Bluetooth="Bluetooth",e.Bookmarks="Bookmarks",e.Caution="Caution",e.ColorPanel="ColorPanel",e.ColumnView="ColumnView",e.Computer="Computer",e.EnterFullScreen="EnterFullScreen",e.Everyone="Everyone",e.ExitFullScreen="ExitFullScreen",e.FlowView="FlowView",e.Folder="Folder",e.FolderBurnable="FolderBurnable",e.FolderSmart="FolderSmart",e.FollowLinkFreestanding="FollowLinkFreestanding",e.FontPanel="FontPanel",e.GoLeft="GoLeft",e.GoRight="GoRight",e.Home="Home",e.IChatTheater="IChatTheater",e.IconView="IconView",e.Info="Info",e.InvalidDataFreestanding="InvalidDataFreestanding",e.LeftFacingTriangle="LeftFacingTriangle",e.ListView="ListView",e.LockLocked="LockLocked",e.LockUnlocked="LockUnlocked",e.MenuMixedState="MenuMixedState",e.MenuOnState="MenuOnState",e.MobileMe="MobileMe",e.MultipleDocuments="MultipleDocuments",e.Network="Network",e.Path="Path",e.PreferencesGeneral="PreferencesGeneral",e.QuickLook="QuickLook",e.RefreshFreestanding="RefreshFreestanding",e.Refresh="Refresh",e.Remove="Remove",e.RevealFreestanding="RevealFreestanding",e.RightFacingTriangle="RightFacingTriangle",e.Share="Share",e.Slideshow="Slideshow",e.SmartBadge="SmartBadge",e.StatusAvailable="StatusAvailable",e.StatusNone="StatusNone",e.StatusPartiallyAvailable="StatusPartiallyAvailable",e.StatusUnavailable="StatusUnavailable",e.StopProgressFreestanding="StopProgressFreestanding",e.StopProgress="StopProgress",e.TrashEmpty="TrashEmpty",e.TrashFull="TrashFull",e.User="User",e.UserAccounts="UserAccounts",e.UserGroup="UserGroup",e.UserGuest="UserGuest"}(W||(W={}));class G extends M{constructor(e,n){super(e,n,"Icon")}static async new(e){return F("Icon",e).then(([e,n])=>new G(e,n))}async text(){return h("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return h("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return h("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return h("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async setAccelerator(e){return h("plugin:menu|set_accelerator",{rid:this.rid,kind:this.kind,accelerator:e})}async setIcon(e){return h("plugin:menu|set_icon",{rid:this.rid,kind:this.kind,icon:g(e)})}}class j extends M{constructor(e,n){super(e,n,"Predefined")}static async new(e){return F("Predefined",e).then(([e,n])=>new j(e,n))}async text(){return h("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return h("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}}function H([e,n,t]){switch(t){case"Submenu":return new $(e,n);case"Predefined":return new j(e,n);case"Check":return new V(e,n);case"Icon":return new G(e,n);default:return new B(e,n)}}class $ extends M{constructor(e,n){super(e,n,"Submenu")}static async new(e){return F("Submenu",e).then(([e,n])=>new $(e,n))}async text(){return h("plugin:menu|text",{rid:this.rid,kind:this.kind})}async setText(e){return h("plugin:menu|set_text",{rid:this.rid,kind:this.kind,text:e})}async isEnabled(){return h("plugin:menu|is_enabled",{rid:this.rid,kind:this.kind})}async setEnabled(e){return h("plugin:menu|set_enabled",{rid:this.rid,kind:this.kind,enabled:e})}async append(e){return h("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async prepend(e){return h("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async insert(e,n){return h("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e),position:n})}async remove(e){return h("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return h("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(H)}async items(){return h("plugin:menu|items",{rid:this.rid,kind:this.kind}).then(e=>e.map(H))}async get(e){return h("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then(e=>e?H(e):null)}async popup(e,n){var t;return h("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:null!==(t=null==n?void 0:n.label)&&void 0!==t?t:null,at:e instanceof E?e:e?new E(e):null})}async setAsWindowsMenuForNSApp(){return h("plugin:menu|set_as_windows_menu_for_nsapp",{rid:this.rid})}async setAsHelpMenuForNSApp(){return h("plugin:menu|set_as_help_menu_for_nsapp",{rid:this.rid})}async setIcon(e){return h("plugin:menu|set_icon",{rid:this.rid,kind:this.kind,icon:g(e)})}}class q extends M{constructor(e,n){super(e,n,"Menu")}static async new(e){return F("Menu",e).then(([e,n])=>new q(e,n))}static async default(){return h("plugin:menu|create_default").then(([e,n])=>new q(e,n))}async append(e){return h("plugin:menu|append",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async prepend(e){return h("plugin:menu|prepend",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e)})}async insert(e,n){return h("plugin:menu|insert",{rid:this.rid,kind:this.kind,items:(Array.isArray(e)?e:[e]).map(e=>"rid"in e?[e.rid,e.kind]:e),position:n})}async remove(e){return h("plugin:menu|remove",{rid:this.rid,kind:this.kind,item:[e.rid,e.kind]})}async removeAt(e){return h("plugin:menu|remove_at",{rid:this.rid,kind:this.kind,position:e}).then(H)}async items(){return h("plugin:menu|items",{rid:this.rid,kind:this.kind}).then(e=>e.map(H))}async get(e){return h("plugin:menu|get",{rid:this.rid,kind:this.kind,id:e}).then(e=>e?H(e):null)}async popup(e,n){var t;return h("plugin:menu|popup",{rid:this.rid,kind:this.kind,window:null!==(t=null==n?void 0:n.label)&&void 0!==t?t:null,at:e instanceof E?e:e?new E(e):null})}async setAsAppMenu(){return h("plugin:menu|set_as_app_menu",{rid:this.rid}).then(e=>e?new q(e[0],e[1]):null)}async setAsWindowMenu(e){var n;return h("plugin:menu|set_as_window_menu",{rid:this.rid,window:null!==(n=null==e?void 0:e.label)&&void 0!==n?n:null}).then(e=>e?new q(e[0],e[1]):null)}}var J=Object.freeze({__proto__:null,CheckMenuItem:V,IconMenuItem:G,Menu:q,MenuItem:B,get NativeIcon(){return W},PredefinedMenuItem:j,Submenu:$,itemFromKind:H});function Q(){var e,n;window.__TAURI_INTERNALS__=null!==(e=window.__TAURI_INTERNALS__)&&void 0!==e?e:{},window.__TAURI_EVENT_PLUGIN_INTERNALS__=null!==(n=window.__TAURI_EVENT_PLUGIN_INTERNALS__)&&void 0!==n?n:{}}var Z,K=Object.freeze({__proto__:null,clearMocks:function(){"object"==typeof window.__TAURI_INTERNALS__&&(delete window.__TAURI_INTERNALS__.invoke,delete window.__TAURI_INTERNALS__.transformCallback,delete window.__TAURI_INTERNALS__.unregisterCallback,delete window.__TAURI_INTERNALS__.runCallback,delete window.__TAURI_INTERNALS__.callbacks,delete window.__TAURI_INTERNALS__.convertFileSrc,delete window.__TAURI_INTERNALS__.metadata,"object"==typeof window.__TAURI_EVENT_PLUGIN_INTERNALS__&&delete window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener)},mockConvertFileSrc:function(e){Q(),window.__TAURI_INTERNALS__.convertFileSrc=function(n,t="asset"){const i=encodeURIComponent(n);return"windows"===e?`http://${t}.localhost/${i}`:`${t}://localhost/${i}`}},mockIPC:function(e,n){function t(e,n){switch(e){case"plugin:event|listen":return function(e){i.has(e.event)||i.set(e.event,[]);return i.get(e.event).push(e.handler),e.handler}(n);case"plugin:event|emit":return function(e){const n=i.get(e.event)||[];for(const t of n)a(t,e);return null}(n);case"plugin:event|unlisten":return function(e){const n=i.get(e.event);if(n){const t=n.indexOf(e.id);-1!==t&&n.splice(t,1)}}(n)}}Q();const i=new Map,r=new Map;function s(e){r.delete(e)}function a(e,n){const t=r.get(e);t?t(n):console.warn(`[TAURI] Couldn't find callback id ${e}. This might happen when the app is reloaded while Rust is running an asynchronous operation.`)}window.__TAURI_INTERNALS__.invoke=async function(i,r,s){return(null==n?void 0:n.shouldMockEvents)&&function(e){return e.startsWith("plugin:event|")}(i)?t(i,r):e(i,r)},window.__TAURI_INTERNALS__.transformCallback=function(e,n=!1){const t=window.crypto.getRandomValues(new Uint32Array(1))[0];return r.set(t,i=>(n&&s(t),e&&e(i))),t},window.__TAURI_INTERNALS__.unregisterCallback=s,window.__TAURI_INTERNALS__.runCallback=a,window.__TAURI_INTERNALS__.callbacks=r,window.__TAURI_EVENT_PLUGIN_INTERNALS__.unregisterListener=function(e,n){s(n)}},mockWindows:function(e,...n){Q(),window.__TAURI_INTERNALS__.metadata={currentWindow:{label:e},currentWebview:{windowLabel:e,label:e}}}});!function(e){e[e.Audio=1]="Audio",e[e.Cache=2]="Cache",e[e.Config=3]="Config",e[e.Data=4]="Data",e[e.LocalData=5]="LocalData",e[e.Document=6]="Document",e[e.Download=7]="Download",e[e.Picture=8]="Picture",e[e.Public=9]="Public",e[e.Video=10]="Video",e[e.Resource=11]="Resource",e[e.Temp=12]="Temp",e[e.AppConfig=13]="AppConfig",e[e.AppData=14]="AppData",e[e.AppLocalData=15]="AppLocalData",e[e.AppCache=16]="AppCache",e[e.AppLog=17]="AppLog",e[e.Desktop=18]="Desktop",e[e.Executable=19]="Executable",e[e.Font=20]="Font",e[e.Home=21]="Home",e[e.Runtime=22]="Runtime",e[e.Template=23]="Template"}(Z||(Z={}));var Y=Object.freeze({__proto__:null,get BaseDirectory(){return Z},appCacheDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.AppCache})},appConfigDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.AppConfig})},appDataDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.AppData})},appLocalDataDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.AppLocalData})},appLogDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.AppLog})},audioDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Audio})},basename:async function(e,n){return h("plugin:path|basename",{path:e,ext:n})},cacheDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Cache})},configDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Config})},dataDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Data})},delimiter:function(){return window.__TAURI_INTERNALS__.plugins.path.delimiter},desktopDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Desktop})},dirname:async function(e){return h("plugin:path|dirname",{path:e})},documentDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Document})},downloadDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Download})},executableDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Executable})},extname:async function(e){return h("plugin:path|extname",{path:e})},fontDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Font})},homeDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Home})},isAbsolute:async function(e){return h("plugin:path|is_absolute",{path:e})},join:async function(...e){return h("plugin:path|join",{paths:e})},localDataDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.LocalData})},normalize:async function(e){return h("plugin:path|normalize",{path:e})},pictureDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Picture})},publicDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Public})},resolve:async function(...e){return h("plugin:path|resolve",{paths:e})},resolveResource:async function(e){return h("plugin:path|resolve_directory",{directory:Z.Resource,path:e})},resourceDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Resource})},runtimeDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Runtime})},sep:function(){return window.__TAURI_INTERNALS__.plugins.path.sep},tempDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Temp})},templateDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Template})},videoDir:async function(){return h("plugin:path|resolve_directory",{directory:Z.Video})}});class X extends w{constructor(e,n){super(e),this.id=n}static async getById(e){return h("plugin:tray|get_by_id",{id:e}).then(n=>n?new X(n,e):null)}static async removeById(e){return h("plugin:tray|remove_by_id",{id:e})}static async new(e){(null==e?void 0:e.menu)&&(e.menu=[e.menu.rid,e.menu.kind]),(null==e?void 0:e.icon)&&(e.icon=g(e.icon));const n=new c;if(null==e?void 0:e.action){const t=e.action;n.onmessage=e=>t(function(e){const n=e;return n.position=new I(e.position),n.rect.position=new I(e.rect.position),n.rect.size=new k(e.rect.size),n}(e)),delete e.action}return h("plugin:tray|new",{options:null!=e?e:{},handler:n}).then(([e,n])=>new X(e,n))}async setIcon(e){let n=null;return e&&(n=g(e)),h("plugin:tray|set_icon",{rid:this.rid,icon:n})}async setMenu(e){return e&&(e=[e.rid,e.kind]),h("plugin:tray|set_menu",{rid:this.rid,menu:e})}async setTooltip(e){return h("plugin:tray|set_tooltip",{rid:this.rid,tooltip:e})}async setTitle(e){return h("plugin:tray|set_title",{rid:this.rid,title:e})}async setVisible(e){return h("plugin:tray|set_visible",{rid:this.rid,visible:e})}async setTempDirPath(e){return h("plugin:tray|set_temp_dir_path",{rid:this.rid,path:e})}async setIconAsTemplate(e){return h("plugin:tray|set_icon_as_template",{rid:this.rid,asTemplate:e})}async setMenuOnLeftClick(e){return h("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}async setShowMenuOnLeftClick(e){return h("plugin:tray|set_show_menu_on_left_click",{rid:this.rid,onLeft:e})}}var ee,ne,te=Object.freeze({__proto__:null,TrayIcon:X});!function(e){e[e.Critical=1]="Critical",e[e.Informational=2]="Informational"}(ee||(ee={}));class ie{constructor(e){this._preventDefault=!1,this.event=e.event,this.id=e.id}preventDefault(){this._preventDefault=!0}isPreventDefault(){return this._preventDefault}}function re(){return new le(window.__TAURI_INTERNALS__.metadata.currentWindow.label,{skip:!0})}async function se(){return h("plugin:window|get_all_windows").then(e=>e.map(e=>new le(e,{skip:!0})))}!function(e){e.None="none",e.Normal="normal",e.Indeterminate="indeterminate",e.Paused="paused",e.Error="error"}(ne||(ne={}));const ae=["tauri://created","tauri://error"];class le{constructor(e,n={}){var t;this.label=e,this.listeners=Object.create(null),(null==n?void 0:n.skip)||h("plugin:window|create",{options:{...n,parent:"string"==typeof n.parent?n.parent:null===(t=n.parent)||void 0===t?void 0:t.label,label:e}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;return null!==(n=(await se()).find(n=>n.label===e))&&void 0!==n?n:null}static getCurrent(){return re()}static async getAll(){return se()}static async getFocusedWindow(){for(const e of await se())if(await e.isFocused())return e;return null}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"Window",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:L(e,n,{target:{kind:"Window",label:this.label}})}async emit(e,n){if(!ae.includes(e))return C(e,n);for(const t of this.listeners[e]||[])t({event:e,id:-1,payload:n})}async emitTo(e,n,t){if(!ae.includes(n))return x(e,n,t);for(const e of this.listeners[n]||[])e({event:n,id:-1,payload:t})}_handleTauriEvent(e,n){return!!ae.includes(e)&&(e in this.listeners?this.listeners[e].push(n):this.listeners[e]=[n],!0)}async scaleFactor(){return h("plugin:window|scale_factor",{label:this.label})}async innerPosition(){return h("plugin:window|inner_position",{label:this.label}).then(e=>new I(e))}async outerPosition(){return h("plugin:window|outer_position",{label:this.label}).then(e=>new I(e))}async innerSize(){return h("plugin:window|inner_size",{label:this.label}).then(e=>new k(e))}async outerSize(){return h("plugin:window|outer_size",{label:this.label}).then(e=>new k(e))}async isFullscreen(){return h("plugin:window|is_fullscreen",{label:this.label})}async isMinimized(){return h("plugin:window|is_minimized",{label:this.label})}async isMaximized(){return h("plugin:window|is_maximized",{label:this.label})}async isFocused(){return h("plugin:window|is_focused",{label:this.label})}async isDecorated(){return h("plugin:window|is_decorated",{label:this.label})}async isResizable(){return h("plugin:window|is_resizable",{label:this.label})}async isMaximizable(){return h("plugin:window|is_maximizable",{label:this.label})}async isMinimizable(){return h("plugin:window|is_minimizable",{label:this.label})}async isClosable(){return h("plugin:window|is_closable",{label:this.label})}async isVisible(){return h("plugin:window|is_visible",{label:this.label})}async title(){return h("plugin:window|title",{label:this.label})}async theme(){return h("plugin:window|theme",{label:this.label})}async isAlwaysOnTop(){return h("plugin:window|is_always_on_top",{label:this.label})}async center(){return h("plugin:window|center",{label:this.label})}async requestUserAttention(e){let n=null;return e&&(n=e===ee.Critical?{type:"Critical"}:{type:"Informational"}),h("plugin:window|request_user_attention",{label:this.label,value:n})}async setResizable(e){return h("plugin:window|set_resizable",{label:this.label,value:e})}async setEnabled(e){return h("plugin:window|set_enabled",{label:this.label,value:e})}async isEnabled(){return h("plugin:window|is_enabled",{label:this.label})}async setMaximizable(e){return h("plugin:window|set_maximizable",{label:this.label,value:e})}async setMinimizable(e){return h("plugin:window|set_minimizable",{label:this.label,value:e})}async setClosable(e){return h("plugin:window|set_closable",{label:this.label,value:e})}async setTitle(e){return h("plugin:window|set_title",{label:this.label,value:e})}async maximize(){return h("plugin:window|maximize",{label:this.label})}async unmaximize(){return h("plugin:window|unmaximize",{label:this.label})}async toggleMaximize(){return h("plugin:window|toggle_maximize",{label:this.label})}async minimize(){return h("plugin:window|minimize",{label:this.label})}async unminimize(){return h("plugin:window|unminimize",{label:this.label})}async show(){return h("plugin:window|show",{label:this.label})}async hide(){return h("plugin:window|hide",{label:this.label})}async close(){return h("plugin:window|close",{label:this.label})}async destroy(){return h("plugin:window|destroy",{label:this.label})}async setDecorations(e){return h("plugin:window|set_decorations",{label:this.label,value:e})}async setShadow(e){return h("plugin:window|set_shadow",{label:this.label,value:e})}async setEffects(e){return h("plugin:window|set_effects",{label:this.label,value:e})}async clearEffects(){return h("plugin:window|set_effects",{label:this.label,value:null})}async setAlwaysOnTop(e){return h("plugin:window|set_always_on_top",{label:this.label,value:e})}async setAlwaysOnBottom(e){return h("plugin:window|set_always_on_bottom",{label:this.label,value:e})}async setContentProtected(e){return h("plugin:window|set_content_protected",{label:this.label,value:e})}async setSize(e){return h("plugin:window|set_size",{label:this.label,value:e instanceof A?e:new A(e)})}async setMinSize(e){return h("plugin:window|set_min_size",{label:this.label,value:e instanceof A?e:e?new A(e):null})}async setMaxSize(e){return h("plugin:window|set_max_size",{label:this.label,value:e instanceof A?e:e?new A(e):null})}async setSizeConstraints(e){function n(e){return e?{Logical:e}:null}return h("plugin:window|set_size_constraints",{label:this.label,value:{minWidth:n(null==e?void 0:e.minWidth),minHeight:n(null==e?void 0:e.minHeight),maxWidth:n(null==e?void 0:e.maxWidth),maxHeight:n(null==e?void 0:e.maxHeight)}})}async setPosition(e){return h("plugin:window|set_position",{label:this.label,value:e instanceof E?e:new E(e)})}async setFullscreen(e){return h("plugin:window|set_fullscreen",{label:this.label,value:e})}async setSimpleFullscreen(e){return h("plugin:window|set_simple_fullscreen",{label:this.label,value:e})}async setFocus(){return h("plugin:window|set_focus",{label:this.label})}async setFocusable(e){return h("plugin:window|set_focusable",{label:this.label,value:e})}async setIcon(e){return h("plugin:window|set_icon",{label:this.label,value:g(e)})}async setSkipTaskbar(e){return h("plugin:window|set_skip_taskbar",{label:this.label,value:e})}async setCursorGrab(e){return h("plugin:window|set_cursor_grab",{label:this.label,value:e})}async setCursorVisible(e){return h("plugin:window|set_cursor_visible",{label:this.label,value:e})}async setCursorIcon(e){return h("plugin:window|set_cursor_icon",{label:this.label,value:e})}async setBackgroundColor(e){return h("plugin:window|set_background_color",{color:e})}async setCursorPosition(e){return h("plugin:window|set_cursor_position",{label:this.label,value:e instanceof E?e:new E(e)})}async setIgnoreCursorEvents(e){return h("plugin:window|set_ignore_cursor_events",{label:this.label,value:e})}async startDragging(){return h("plugin:window|start_dragging",{label:this.label})}async startResizeDragging(e){return h("plugin:window|start_resize_dragging",{label:this.label,value:e})}async setBadgeCount(e){return h("plugin:window|set_badge_count",{label:this.label,value:e})}async setBadgeLabel(e){return h("plugin:window|set_badge_label",{label:this.label,value:e})}async setOverlayIcon(e){return h("plugin:window|set_overlay_icon",{label:this.label,value:e?g(e):void 0})}async setProgressBar(e){return h("plugin:window|set_progress_bar",{label:this.label,value:e})}async setVisibleOnAllWorkspaces(e){return h("plugin:window|set_visible_on_all_workspaces",{label:this.label,value:e})}async setTitleBarStyle(e){return h("plugin:window|set_title_bar_style",{label:this.label,value:e})}async setTheme(e){return h("plugin:window|set_theme",{label:this.label,value:e})}async onResized(e){return this.listen(R.WINDOW_RESIZED,n=>{n.payload=new k(n.payload),e(n)})}async onMoved(e){return this.listen(R.WINDOW_MOVED,n=>{n.payload=new I(n.payload),e(n)})}async onCloseRequested(e){return this.listen(R.WINDOW_CLOSE_REQUESTED,async n=>{const t=new ie(n);await e(t),t.isPreventDefault()||await this.destroy()})}async onDragDropEvent(e){const n=await this.listen(R.DRAG_ENTER,n=>{e({...n,payload:{type:"enter",paths:n.payload.paths,position:new I(n.payload.position)}})}),t=await this.listen(R.DRAG_OVER,n=>{e({...n,payload:{type:"over",position:new I(n.payload.position)}})}),i=await this.listen(R.DRAG_DROP,n=>{e({...n,payload:{type:"drop",paths:n.payload.paths,position:new I(n.payload.position)}})}),r=await this.listen(R.DRAG_LEAVE,n=>{e({...n,payload:{type:"leave"}})});return()=>{n(),i(),t(),r()}}async onFocusChanged(e){const n=await this.listen(R.WINDOW_FOCUS,n=>{e({...n,payload:!0})}),t=await this.listen(R.WINDOW_BLUR,n=>{e({...n,payload:!1})});return()=>{n(),t()}}async onScaleChanged(e){return this.listen(R.WINDOW_SCALE_FACTOR_CHANGED,e)}async onThemeChanged(e){return this.listen(R.WINDOW_THEME_CHANGED,e)}}var oe,ue,ce,de;function pe(e){return null===e?null:{name:e.name,scaleFactor:e.scaleFactor,position:new I(e.position),size:new k(e.size),workArea:{position:new I(e.workArea.position),size:new k(e.workArea.size)}}}!function(e){e.Disabled="disabled",e.Throttle="throttle",e.Suspend="suspend"}(oe||(oe={})),function(e){e.Default="default",e.FluentOverlay="fluentOverlay"}(ue||(ue={})),function(e){e.AppearanceBased="appearanceBased",e.Light="light",e.Dark="dark",e.MediumLight="mediumLight",e.UltraDark="ultraDark",e.Titlebar="titlebar",e.Selection="selection",e.Menu="menu",e.Popover="popover",e.Sidebar="sidebar",e.HeaderView="headerView",e.Sheet="sheet",e.WindowBackground="windowBackground",e.HudWindow="hudWindow",e.FullScreenUI="fullScreenUI",e.Tooltip="tooltip",e.ContentBackground="contentBackground",e.UnderWindowBackground="underWindowBackground",e.UnderPageBackground="underPageBackground",e.Mica="mica",e.Blur="blur",e.Acrylic="acrylic",e.Tabbed="tabbed",e.TabbedDark="tabbedDark",e.TabbedLight="tabbedLight"}(ce||(ce={})),function(e){e.FollowsWindowActiveState="followsWindowActiveState",e.Active="active",e.Inactive="inactive"}(de||(de={}));var he=Object.freeze({__proto__:null,CloseRequestedEvent:ie,get Effect(){return ce},get EffectState(){return de},LogicalPosition:T,LogicalSize:v,PhysicalPosition:I,PhysicalSize:k,get ProgressBarStatus(){return ne},get UserAttentionType(){return ee},Window:le,availableMonitors:async function(){return h("plugin:window|available_monitors").then(e=>e.map(pe))},currentMonitor:async function(){return h("plugin:window|current_monitor").then(pe)},cursorPosition:async function(){return h("plugin:window|cursor_position").then(e=>new I(e))},getAllWindows:se,getCurrentWindow:re,monitorFromPoint:async function(e,n){return h("plugin:window|monitor_from_point",{x:e,y:n}).then(pe)},primaryMonitor:async function(){return h("plugin:window|primary_monitor").then(pe)}});function we(){return new ge(re(),window.__TAURI_INTERNALS__.metadata.currentWebview.label,{skip:!0})}async function _e(){return h("plugin:webview|get_all_webviews").then(e=>e.map(e=>new ge(new le(e.windowLabel,{skip:!0}),e.label,{skip:!0})))}const ye=["tauri://created","tauri://error"];class ge{constructor(e,n,t){this.window=e,this.label=n,this.listeners=Object.create(null),(null==t?void 0:t.skip)||h("plugin:webview|create_webview",{windowLabel:e.label,options:{...t,label:n}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;return null!==(n=(await _e()).find(n=>n.label===e))&&void 0!==n?n:null}static getCurrent(){return we()}static async getAll(){return _e()}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"Webview",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:L(e,n,{target:{kind:"Webview",label:this.label}})}async emit(e,n){if(!ye.includes(e))return C(e,n);for(const t of this.listeners[e]||[])t({event:e,id:-1,payload:n})}async emitTo(e,n,t){if(!ye.includes(n))return x(e,n,t);for(const e of this.listeners[n]||[])e({event:n,id:-1,payload:t})}_handleTauriEvent(e,n){return!!ye.includes(e)&&(e in this.listeners?this.listeners[e].push(n):this.listeners[e]=[n],!0)}async position(){return h("plugin:webview|webview_position",{label:this.label}).then(e=>new I(e))}async size(){return h("plugin:webview|webview_size",{label:this.label}).then(e=>new k(e))}async close(){return h("plugin:webview|webview_close",{label:this.label})}async setSize(e){return h("plugin:webview|set_webview_size",{label:this.label,value:e instanceof A?e:new A(e)})}async setPosition(e){return h("plugin:webview|set_webview_position",{label:this.label,value:e instanceof E?e:new E(e)})}async setFocus(){return h("plugin:webview|set_webview_focus",{label:this.label})}async setAutoResize(e){return h("plugin:webview|set_webview_auto_resize",{label:this.label,value:e})}async hide(){return h("plugin:webview|webview_hide",{label:this.label})}async show(){return h("plugin:webview|webview_show",{label:this.label})}async setZoom(e){return h("plugin:webview|set_webview_zoom",{label:this.label,value:e})}async reparent(e){return h("plugin:webview|reparent",{label:this.label,window:"string"==typeof e?e:e.label})}async clearAllBrowsingData(){return h("plugin:webview|clear_all_browsing_data")}async setBackgroundColor(e){return h("plugin:webview|set_webview_background_color",{color:e})}async onDragDropEvent(e){const n=await this.listen(R.DRAG_ENTER,n=>{e({...n,payload:{type:"enter",paths:n.payload.paths,position:new I(n.payload.position)}})}),t=await this.listen(R.DRAG_OVER,n=>{e({...n,payload:{type:"over",position:new I(n.payload.position)}})}),i=await this.listen(R.DRAG_DROP,n=>{e({...n,payload:{type:"drop",paths:n.payload.paths,position:new I(n.payload.position)}})}),r=await this.listen(R.DRAG_LEAVE,n=>{e({...n,payload:{type:"leave"}})});return()=>{n(),i(),t(),r()}}}var be,me,fe=Object.freeze({__proto__:null,Webview:ge,getAllWebviews:_e,getCurrentWebview:we});function ve(){const e=we();return new Ae(e.label,{skip:!0})}async function ke(){return h("plugin:window|get_all_windows").then(e=>e.map(e=>new Ae(e,{skip:!0})))}class Ae{constructor(e,n={}){var t;this.label=e,this.listeners=Object.create(null),(null==n?void 0:n.skip)||h("plugin:webview|create_webview_window",{options:{...n,parent:"string"==typeof n.parent?n.parent:null===(t=n.parent)||void 0===t?void 0:t.label,label:e}}).then(async()=>this.emit("tauri://created")).catch(async e=>this.emit("tauri://error",e))}static async getByLabel(e){var n;const t=null!==(n=(await ke()).find(n=>n.label===e))&&void 0!==n?n:null;return t?new Ae(t.label,{skip:!0}):null}static getCurrent(){return ve()}static async getAll(){return ke()}async listen(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:N(e,n,{target:{kind:"WebviewWindow",label:this.label}})}async once(e,n){return this._handleTauriEvent(e,n)?()=>{const t=this.listeners[e];t.splice(t.indexOf(n),1)}:L(e,n,{target:{kind:"WebviewWindow",label:this.label}})}async setBackgroundColor(e){return h("plugin:window|set_background_color",{color:e}).then(()=>h("plugin:webview|set_webview_background_color",{color:e}))}}be=Ae,me=[le,ge],(Array.isArray(me)?me:[me]).forEach(e=>{Object.getOwnPropertyNames(e.prototype).forEach(n=>{var t;"object"==typeof be.prototype&&be.prototype&&n in be.prototype||Object.defineProperty(be.prototype,n,null!==(t=Object.getOwnPropertyDescriptor(e.prototype,n))&&void 0!==t?t:Object.create(null))})});var Te=Object.freeze({__proto__:null,WebviewWindow:Ae,getAllWebviewWindows:ke,getCurrentWebviewWindow:ve});return e.app=f,e.core=_,e.dpi=D,e.event=O,e.image=m,e.menu=J,e.mocks=K,e.path=Y,e.tray=te,e.webview=fe,e.webviewWindow=Te,e.window=he,e}({});window.__TAURI__=__TAURI_IIFE__; diff --git a/crates/tauri/scripts/ipc-protocol.js b/crates/tauri/scripts/ipc-protocol.js index 7f8f0e29a..9ca244053 100644 --- a/crates/tauri/scripts/ipc-protocol.js +++ b/crates/tauri/scripts/ipc-protocol.js @@ -52,19 +52,21 @@ return response.arrayBuffer().then((r) => [callbackId, r]) } }) - .catch((e) => { - console.warn( - 'IPC custom protocol failed, Tauri will now use the postMessage interface instead', - e - ) - // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error) - // so we need to fallback to the postMessage interface - customProtocolIpcFailed = true - sendIpcMessage(message) - }) - .then(([callbackId, data]) => { - window.__TAURI_INTERNALS__.runCallback(callbackId, data) - }) + .then( + ([callbackId, data]) => { + window.__TAURI_INTERNALS__.runCallback(callbackId, data) + }, + (e) => { + console.warn( + 'IPC custom protocol failed, Tauri will now use the postMessage interface instead', + e + ) + // failed to use the custom protocol IPC (either the webview blocked a custom protocol or it was a CSP error) + // so we need to fallback to the postMessage interface + customProtocolIpcFailed = true + sendIpcMessage(message) + } + ) } else { // otherwise use the postMessage interface const { data } = processIpcMessage({ @@ -78,6 +80,7 @@ payload, __TAURI_INVOKE_KEY__ }) + // `window.ipc.postMessage` came from `tauri-runtime-wry` > `wry` [`with_ipc_handler`](https://github.com/tauri-apps/wry/blob/a0403b9e2f1ff9d73be7dce1184f058afcaa1d82/src/lib.rs#L1130) window.ipc.postMessage(data) } } diff --git a/crates/tauri/src/app.rs b/crates/tauri/src/app.rs index 06a3abe44..e53f22675 100644 --- a/crates/tauri/src/app.rs +++ b/crates/tauri/src/app.rs @@ -278,12 +278,11 @@ impl AssetResolver { /// were configured with [`crate::webview::WebviewBuilder::use_https_scheme`] or `tauri.conf.json > app > windows > useHttpsScheme`. /// If you are resolving an asset for a webview with a more dynamic configuration, see [`AssetResolver::get_for_scheme`]. /// - /// Resolves to the embedded asset that is part of the app - /// in dev when [`devUrl`](https://v2.tauri.app/reference/config/#devurl) points to a folder in your filesystem - /// or in production when [`frontendDist`](https://v2.tauri.app/reference/config/#frontenddist) - /// points to your frontend assets. + /// In production, this resolves to the embedded asset bundled in the app executable + /// which contains your frontend assets in [`frontendDist`](https://v2.tauri.app/reference/config/#frontenddist) during build time. /// - /// Fallbacks to reading the asset from the [distDir] folder so the behavior is consistent in development. + /// In dev mode, if [`devUrl`](https://v2.tauri.app/reference/config/#devurl) is set, we don't bundle the assets to reduce re-builds, + /// and this will fall back to read from `frontendDist` directly. /// Note that the dist directory must exist so you might need to build your frontend assets first. pub fn get(&self, path: String) -> Option { let use_https_scheme = self @@ -301,9 +300,8 @@ impl AssetResolver { pub fn get_for_scheme(&self, path: String, use_https_scheme: bool) -> Option { #[cfg(dev)] { - // on dev if the devPath is a path to a directory we have the embedded assets - // so we can use get_asset() directly - // we only fallback to reading from distDir directly if we're using an external URL (which is likely) + // We don't bundle the assets when in dev mode and `devUrl` is set, so fall back to read from `frontendDist` directly + // TODO: Maybe handle `FrontendDist::Files` as well if let (Some(_), Some(crate::utils::config::FrontendDist::Directory(dist_path))) = ( &self.manager.config().build.dev_url, &self.manager.config().build.frontend_dist, @@ -386,7 +384,7 @@ impl AppHandle { #[cfg(target_vendor = "apple")] impl AppHandle { - /// Fetches all Data Store Indentifiers by this app + /// Fetches all Data Store Identifiers by this app /// /// Needs to be called from Main Thread pub async fn fetch_data_store_identifiers(&self) -> crate::Result> { @@ -513,7 +511,7 @@ impl AppHandle { /// } /// /// let plugin = init_plugin(); - /// // `.name()` requires the `PLugin` trait import + /// // `.name()` requires the `Plugin` trait import /// let plugin_name = plugin.name(); /// tauri::Builder::default() /// .plugin(plugin) @@ -1577,7 +1575,7 @@ impl Builder { /// Append a custom initialization script. /// - /// Allow to append custom initialization script instend of replacing entire invoke system. + /// Allow to append custom initialization script instead of replacing entire invoke system. /// /// # Examples /// @@ -1990,13 +1988,13 @@ tauri::Builder::default() >( mut self, uri_scheme: N, - protocol: H, + protocol_handler: H, ) -> Self { self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(move |ctx, request, responder| { - responder.respond(protocol(ctx, request)) + handler: Box::new(move |ctx, request, responder| { + responder.respond(protocol_handler(ctx, request)) }), }), ); @@ -2032,8 +2030,8 @@ tauri::Builder::default() /// .body("failed to read file".as_bytes().to_vec()) /// .unwrap() /// ); - /// } - /// }); + /// } + /// }); /// }); /// ``` /// @@ -2054,12 +2052,12 @@ tauri::Builder::default() >( mut self, uri_scheme: N, - protocol: H, + protocol_handler: H, ) -> Self { self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(protocol), + handler: Box::new(protocol_handler), }), ); self diff --git a/crates/tauri/src/app/plugin.rs b/crates/tauri/src/app/plugin.rs index d070bab27..8b9d3f358 100644 --- a/crates/tauri/src/app/plugin.rs +++ b/crates/tauri/src/app/plugin.rs @@ -132,5 +132,16 @@ pub fn init() -> TauriPlugin { set_dock_visibility, bundle_type, ]) + .setup(|_app, _api| { + #[cfg(target_os = "android")] + { + let handle = _api.register_android_plugin("app.tauri", "AppPlugin")?; + _app.manage(AppPlugin(handle)); + } + Ok(()) + }) .build() } + +#[cfg(target_os = "android")] +pub(crate) struct AppPlugin(pub crate::plugin::PluginHandle); diff --git a/crates/tauri/src/ios.rs b/crates/tauri/src/ios.rs index 75aaf7569..b0f3a59bf 100644 --- a/crates/tauri/src/ios.rs +++ b/crates/tauri/src/ios.rs @@ -46,3 +46,4 @@ swift!(pub fn register_plugin( webview: *const c_void )); swift!(pub fn on_webview_created(webview: *const c_void, controller: *const c_void)); +swift!(pub fn log_stdout()); 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/ipc/mod.rs b/crates/tauri/src/ipc/mod.rs index 3b1d8cd1f..aff4d4891 100644 --- a/crates/tauri/src/ipc/mod.rs +++ b/crates/tauri/src/ipc/mod.rs @@ -345,7 +345,7 @@ impl InvokeResolver { F: Future> + Send + 'static, { // Dynamic dispatch the call in dev for a faster compile time - // TODO: Revisit this and see if we can do this for the release build as well if the performace hit is not a problem + // TODO: Revisit this and see if we can do this for the release build as well if the performance hit is not a problem #[cfg(debug_assertions)] { self.respond_async_serialized_dyn(Box::pin(task)) diff --git a/crates/tauri/src/lib.rs b/crates/tauri/src/lib.rs index 68a58edcc..d56ba8736 100644 --- a/crates/tauri/src/lib.rs +++ b/crates/tauri/src/lib.rs @@ -248,38 +248,10 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[cfg(target_os = "ios")] #[doc(hidden)] pub fn log_stdout() { - use std::{ - ffi::CString, - fs::File, - io::{BufRead, BufReader}, - os::unix::prelude::*, - thread, - }; - - let mut logpipe: [RawFd; 2] = Default::default(); + #[cfg(target_os = "ios")] unsafe { - libc::pipe(logpipe.as_mut_ptr()); - libc::dup2(logpipe[1], libc::STDOUT_FILENO); - libc::dup2(logpipe[1], libc::STDERR_FILENO); + crate::ios::log_stdout(); } - thread::spawn(move || unsafe { - let file = File::from_raw_fd(logpipe[0]); - let mut reader = BufReader::new(file); - let mut buffer = String::new(); - loop { - buffer.clear(); - if let Ok(len) = reader.read_line(&mut buffer) { - if len == 0 { - break; - } else if let Ok(msg) = CString::new(buffer.as_bytes()) - .map_err(|_| ()) - .and_then(|c| c.into_string().map_err(|_| ())) - { - log::info!("{}", msg); - } - } - } - }); } /// The user event type. @@ -296,7 +268,7 @@ pub enum EventLoopMessage { /// The webview runtime interface. A wrapper around [`runtime::Runtime`] with the proper user event type associated. pub trait Runtime: runtime::Runtime {} -/// The webview runtime handle. A wrapper arond [`runtime::RuntimeHandle`] with the proper user event type associated. +/// The webview runtime handle. A wrapper around [`runtime::RuntimeHandle`] with the proper user event type associated. pub trait RuntimeHandle: runtime::RuntimeHandle {} impl> Runtime for W {} diff --git a/crates/tauri/src/manager/mod.rs b/crates/tauri/src/manager/mod.rs index b97d9fbec..25ae8eaab 100644 --- a/crates/tauri/src/manager/mod.rs +++ b/crates/tauri/src/manager/mod.rs @@ -129,14 +129,7 @@ fn replace_csp_nonce( ) { let mut nonces = Vec::new(); *asset = replace_with_callback(asset, token, || { - #[cfg(target_pointer_width = "64")] - let mut raw = [0u8; 8]; - #[cfg(target_pointer_width = "32")] - let mut raw = [0u8; 4]; - #[cfg(target_pointer_width = "16")] - let mut raw = [0u8; 2]; - getrandom::fill(&mut raw).expect("failed to get random bytes"); - let nonce = usize::from_ne_bytes(raw); + let nonce = getrandom::u64().expect("failed to get random bytes"); nonces.push(nonce); nonce.to_string() }); @@ -265,7 +258,7 @@ impl AppManager { crate::app::GlobalTrayIconEventListener>, >, window_event_listeners: Vec>, - webiew_event_listeners: Vec>, + webview_event_listeners: Vec>, #[cfg(desktop)] window_menu_event_listeners: HashMap< String, crate::app::GlobalMenuEventListener>, @@ -292,7 +285,7 @@ impl AppManager { invoke_handler, on_page_load, uri_scheme_protocols: Mutex::new(uri_scheme_protocols), - event_listeners: Arc::new(webiew_event_listeners), + event_listeners: Arc::new(webview_event_listeners), invoke_initialization_script, invoke_key: invoke_key.clone(), }, @@ -333,25 +326,9 @@ impl AppManager { self.state.clone() } - /// Get the base path to serve data from. - /// - /// * In dev mode, this will be based on the `devUrl` configuration value. - /// * Otherwise, this will be based on the `frontendDist` configuration value. - #[cfg(not(dev))] - fn base_path(&self) -> Option<&Url> { - use crate::utils::config::FrontendDist; - match self.config.build.frontend_dist.as_ref() { - Some(FrontendDist::Url(url)) => Some(url), - _ => None, - } - } - - #[cfg(dev)] - fn base_path(&self) -> Option<&Url> { - self.config.build.dev_url.as_ref() - } - - pub(crate) fn protocol_url(&self, https: bool) -> Cow<'_, Url> { + /// The `tauri` custom protocol URL we use to serve the embedded assets. + /// Returns `tauri://localhost` or its `wry` workaround URL `http://tauri.localhost`/`https://tauri.localhost` + pub(crate) fn tauri_protocol_url(&self, https: bool) -> Cow<'_, Url> { if cfg!(windows) || cfg!(target_os = "android") { let scheme = if https { "https" } else { "http" }; Cow::Owned(Url::parse(&format!("{scheme}://tauri.localhost")).unwrap()) @@ -360,13 +337,24 @@ impl AppManager { } } - /// Get the base URL to use for webview requests. + /// Get the base app URL for [`WebviewUrl::App`](tauri_utils::config::WebviewUrl::App). /// - /// In dev mode, this will be based on the `devUrl` configuration value. - pub(crate) fn get_url(&self, https: bool) -> Cow<'_, Url> { - match self.base_path() { - Some(url) => Cow::Borrowed(url), - _ => self.protocol_url(https), + /// * In dev mode, this is the [`devUrl`](tauri_utils::config::BuildConfig::dev_url) configuration value if it exsits. + /// * In production mode, this is the [`frontendDist`](tauri_utils::config::BuildConfig::frontend_dist) configuration value if it's a [`FrontendDist::Url`](tauri_utils::config::FrontendDist::Url). + /// * Returns [`Self::tauri_protocol_url`] (e.g. `tauri://localhost`) otherwise. + pub(crate) fn get_app_url(&self, https: bool) -> Cow<'_, Url> { + #[cfg(dev)] + let url = self.config.build.dev_url.as_ref(); + #[cfg(not(dev))] + let url = match self.config.build.frontend_dist.as_ref() { + Some(crate::utils::config::FrontendDist::Url(url)) => Some(url), + _ => None, + }; + + if let Some(url) = url { + Cow::Borrowed(url) + } else { + self.tauri_protocol_url(https) } } @@ -790,7 +778,7 @@ mod test { #[cfg(custom_protocol)] { assert_eq!( - manager.get_url(false).to_string(), + manager.get_app_url(false).to_string(), if cfg!(windows) || cfg!(target_os = "android") { "http://tauri.localhost/" } else { @@ -798,7 +786,7 @@ mod test { } ); assert_eq!( - manager.get_url(true).to_string(), + manager.get_app_url(true).to_string(), if cfg!(windows) || cfg!(target_os = "android") { "https://tauri.localhost/" } else { @@ -808,7 +796,10 @@ mod test { } #[cfg(dev)] - assert_eq!(manager.get_url(false).to_string(), "http://localhost:4000/"); + assert_eq!( + manager.get_app_url(false).to_string(), + "http://localhost:4000/" + ); } struct EventSetup { diff --git a/crates/tauri/src/manager/webview.rs b/crates/tauri/src/manager/webview.rs index 623b31d24..98c470b76 100644 --- a/crates/tauri/src/manager/webview.rs +++ b/crates/tauri/src/manager/webview.rs @@ -60,7 +60,7 @@ pub(crate) struct IpcJavascript<'a> { pub struct UriSchemeProtocol { /// Handler for protocol #[allow(clippy::type_complexity)] - pub protocol: + pub handler: Box, http::Request>, UriSchemeResponder) + Send + Sync>, } @@ -231,7 +231,7 @@ impl WebviewManager { app_handle: &app_handle, webview_label: webview_id, }; - (protocol.protocol)(context, request, UriSchemeResponder(responder)) + (protocol.handler)(context, request, UriSchemeResponder(responder)) }); } @@ -413,7 +413,7 @@ impl WebviewManager { #[allow(unused_mut)] // mut url only for the data-url parsing let mut url = match &pending.webview_attributes.url { WebviewUrl::App(path) => { - let app_url = app_manager.get_url(pending.webview_attributes.use_https_scheme); + let app_url = app_manager.get_app_url(pending.webview_attributes.use_https_scheme); let url = if PROXY_DEV_SERVER && is_local_network_url(&app_url) { Cow::Owned(Url::parse("tauri://localhost").unwrap()) } else { @@ -431,7 +431,7 @@ impl WebviewManager { } } WebviewUrl::External(url) => { - let config_url = app_manager.get_url(pending.webview_attributes.use_https_scheme); + let config_url = app_manager.get_app_url(pending.webview_attributes.use_https_scheme); let is_app_url = config_url.make_relative(url).is_some(); let mut url = url.clone(); if is_app_url && PROXY_DEV_SERVER && is_local_network_url(&url) { diff --git a/crates/tauri/src/path/android.rs b/crates/tauri/src/path/android.rs index aa185f84f..451032ee7 100644 --- a/crates/tauri/src/path/android.rs +++ b/crates/tauri/src/path/android.rs @@ -4,10 +4,7 @@ use super::Result; use crate::{plugin::PluginHandle, Runtime}; -use std::{ - ffi::OsStr, - path::{Path, PathBuf}, -}; +use std::path::{Path, PathBuf}; /// A helper class to access the mobile path APIs. pub struct PathResolver(pub(crate) PluginHandle); diff --git a/crates/tauri/src/path/plugin.rs b/crates/tauri/src/path/plugin.rs index 4368531b1..e65e5ddfd 100644 --- a/crates/tauri/src/path/plugin.rs +++ b/crates/tauri/src/path/plugin.rs @@ -17,7 +17,7 @@ use crate::{ /// fn normalize_path(path: &Path) -> PathBuf { let mut components = path.components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() { components.next(); PathBuf::from(c.as_os_str()) } else { @@ -47,7 +47,7 @@ fn normalize_path(path: &Path) -> PathBuf { /// fn normalize_path_no_absolute(path: &Path) -> PathBuf { let mut components = path.components().peekable(); - let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { + let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().copied() { components.next(); PathBuf::from(c.as_os_str()) } else { diff --git a/crates/tauri/src/pattern.rs b/crates/tauri/src/pattern.rs index 5048e86e0..c88f11ab3 100644 --- a/crates/tauri/src/pattern.rs +++ b/crates/tauri/src/pattern.rs @@ -64,23 +64,17 @@ impl From<&Pattern> for PatternObject { /// Where the JavaScript is injected to #[cfg(feature = "isolation")] -#[derive(Debug, Serialize)] +#[derive(Default, Debug, Serialize)] #[serde(rename_all = "lowercase")] pub(crate) enum IsolationSide { /// Original frame, the Brownfield application + #[default] Original, /// Secure frame, the isolation security application #[allow(dead_code)] Secure, } -#[cfg(feature = "isolation")] -impl Default for IsolationSide { - fn default() -> Self { - Self::Original - } -} - #[derive(Template)] #[default_template("../scripts/pattern.js")] pub(crate) struct PatternJavascript { diff --git a/crates/tauri/src/plugin.rs b/crates/tauri/src/plugin.rs index e1624377c..3a22de7bc 100644 --- a/crates/tauri/src/plugin.rs +++ b/crates/tauri/src/plugin.rs @@ -90,7 +90,7 @@ pub trait Plugin: Send { #[allow(unused_variables)] fn webview_created(&mut self, webview: Webview) {} - /// Callback invoked when webview tries to navigate to the given Url. Returning falses cancels navigation. + /// Callback invoked when webview tries to navigate to the given Url. Returning false cancels navigation. #[allow(unused_variables)] fn on_navigation(&mut self, webview: &Webview, url: &Url) -> bool { true @@ -642,13 +642,13 @@ impl Builder { >( mut self, uri_scheme: N, - protocol: H, + protocol_handler: H, ) -> Self { self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(move |ctx, request, responder| { - responder.respond(protocol(ctx, request)) + handler: Box::new(move |ctx, request, responder| { + responder.respond(protocol_handler(ctx, request)) }), }), ); @@ -712,12 +712,12 @@ impl Builder { >( mut self, uri_scheme: N, - protocol: H, + protocol_handler: H, ) -> Self { self.uri_scheme_protocols.insert( uri_scheme.into(), Arc::new(UriSchemeProtocol { - protocol: Box::new(protocol), + handler: Box::new(protocol_handler), }), ); self diff --git a/crates/tauri/src/process.rs b/crates/tauri/src/process.rs index 76937b1fe..0264b5702 100644 --- a/crates/tauri/src/process.rs +++ b/crates/tauri/src/process.rs @@ -116,7 +116,7 @@ fn restart_macos_app(current_binary: &std::path::Path, env: &Env) { .and_then(|v| v.as_string()) { if let Err(e) = Command::new(macos_directory.join(binary_name)) - .args(env.args_os.iter().skip(1).collect::>()) + .args(env.args_os.iter().skip(1)) .spawn() { log::error!("failed to restart app: {e}"); 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/protocol/mod.rs b/crates/tauri/src/protocol/mod.rs index 2298bd51f..8542e2ae0 100644 --- a/crates/tauri/src/protocol/mod.rs +++ b/crates/tauri/src/protocol/mod.rs @@ -2,6 +2,8 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT +//! Custom protocol handlers + #[cfg(feature = "protocol-asset")] pub mod asset; #[cfg(feature = "isolation")] diff --git a/crates/tauri/src/protocol/tauri.rs b/crates/tauri/src/protocol/tauri.rs index 52ba6119d..a346754f0 100644 --- a/crates/tauri/src/protocol/tauri.rs +++ b/crates/tauri/src/protocol/tauri.rs @@ -32,7 +32,7 @@ pub fn get( #[cfg(all(dev, mobile))] let url = { let mut url = manager - .get_url(window_origin.starts_with("https")) + .get_app_url(window_origin.starts_with("https")) .as_str() .to_string(); if url.ends_with('/') { @@ -95,9 +95,9 @@ fn get_response( let path = path .strip_prefix("tauri://localhost") .map(|p| p.to_string()) - // the `strip_prefix` only returns None when a request is made to `https://tauri.$P` on Windows + // the `strip_prefix` only returns None when a request is made to `https://tauri.$P` on Windows and Android // where `$P` is not `localhost/*` - .unwrap_or_else(|| "".to_string()); + .unwrap_or_default(); let mut builder = HttpResponse::builder() .add_configured_headers(manager.config.app.security.headers.as_ref()) @@ -114,6 +114,11 @@ fn get_response( decoded_path.trim_start_matches('/') ); + #[cfg(feature = "rustls-tls")] + if rustls::crypto::CryptoProvider::get_default().is_none() { + let _ = rustls::crypto::ring::default_provider().install_default(); + } + let mut client = reqwest::ClientBuilder::new(); if url.starts_with("https://") { @@ -126,10 +131,9 @@ fn get_response( ))] { log::info!("adding dev server root certificate"); - client = client.add_root_certificate( - reqwest::Certificate::from_pem(cert_pem.as_bytes()) - .expect("failed to parse TAURI_DEV_ROOT_CERTIFICATE"), - ); + let certificate = reqwest::Certificate::from_pem(cert_pem.as_bytes()) + .expect("failed to parse TAURI_DEV_ROOT_CERTIFICATE"); + client = client.tls_certs_merge([certificate]); } #[cfg(not(any( diff --git a/crates/tauri/src/test/mock_runtime.rs b/crates/tauri/src/test/mock_runtime.rs index 16b136ef7..5fbedd013 100644 --- a/crates/tauri/src/test/mock_runtime.rs +++ b/crates/tauri/src/test/mock_runtime.rs @@ -1146,7 +1146,14 @@ impl Runtime for MockRuntime { Ok(Self::init()) } - #[cfg(any(windows, target_os = "linux"))] + #[cfg(any( + windows, + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "netbsd", + target_os = "openbsd" + ))] fn new_any_thread(_args: RuntimeInitArgs) -> Result { Ok(Self::init()) } 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/tray/mod.rs b/crates/tauri/src/tray/mod.rs index 5980844c9..5ecef674a 100644 --- a/crates/tauri/src/tray/mod.rs +++ b/crates/tauri/src/tray/mod.rs @@ -19,20 +19,15 @@ use std::path::Path; pub use tray_icon::TrayIconId; /// Describes the mouse button state. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize)] +#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, Serialize)] pub enum MouseButtonState { /// Mouse button pressed. + #[default] Up, /// Mouse button released. Down, } -impl Default for MouseButtonState { - fn default() -> Self { - Self::Up - } -} - impl From for MouseButtonState { fn from(value: tray_icon::MouseButtonState) -> Self { match value { @@ -43,9 +38,10 @@ impl From for MouseButtonState { } /// Describes which mouse button triggered the event.. -#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, Serialize, Default)] pub enum MouseButton { /// Left mouse button. + #[default] Left, /// Right mouse button. Right, @@ -53,12 +49,6 @@ pub enum MouseButton { Middle, } -impl Default for MouseButton { - fn default() -> Self { - Self::Left - } -} - impl From for MouseButton { fn from(value: tray_icon::MouseButton) -> Self { match value { @@ -73,7 +63,7 @@ impl From for MouseButton { /// /// ## Platform-specific: /// -/// - **Linux**: Unsupported. The event is not emmited even though the icon is shown +/// - **Linux**: Unsupported. The event is not emitted even though the icon is shown /// and will still show a context menu on right click. #[derive(Debug, Clone, Serialize)] #[serde(tag = "type")] @@ -314,7 +304,7 @@ impl TrayIconBuilder { /// - **Linux:** Unsupported. #[deprecated( since = "2.2.0", - note = "Use `TrayIconBuiler::show_menu_on_left_click` instead." + note = "Use `TrayIconBuilder::show_menu_on_left_click` instead." )] pub fn menu_on_left_click(mut self, enable: bool) -> Self { self.inner = self.inner.with_menu_on_left_click(enable); diff --git a/crates/tauri/src/webview/mod.rs b/crates/tauri/src/webview/mod.rs index c185e7c62..8842382bf 100644 --- a/crates/tauri/src/webview/mod.rs +++ b/crates/tauri/src/webview/mod.rs @@ -1202,7 +1202,7 @@ fn main() { self } - /// Allows overriding the the keyboard accessory view on iOS. + /// Allows overriding the keyboard accessory view on iOS. /// Returning `None` effectively removes the view. /// /// The closure parameter is the webview instance. @@ -1682,7 +1682,7 @@ tauri::Builder::default() // if from `tauri://` custom protocol ({ - let protocol_url = self.manager().protocol_url(uses_https); + let protocol_url = self.manager().tauri_protocol_url(uses_https); current_url.scheme() == protocol_url.scheme() && current_url.domain() == protocol_url.domain() }) || @@ -1690,7 +1690,7 @@ tauri::Builder::default() // or if relative to `devUrl` or `frontendDist` self .manager() - .get_url(uses_https) + .get_app_url(uses_https) .make_relative(current_url) .is_some() @@ -1706,7 +1706,7 @@ tauri::Builder::default() // so we check using the first part of the domain #[cfg(any(windows, target_os = "android"))] let local = { - let protocol_url = self.manager().protocol_url(uses_https); + let protocol_url = self.manager().tauri_protocol_url(uses_https); let maybe_protocol = current_url .domain() .and_then(|d| d .split_once('.')) @@ -2068,7 +2068,7 @@ tauri::Builder::default() /// Specify the webview background color. /// - /// ## Platfrom-specific: + /// ## Platform-specific: /// /// - **macOS / iOS**: Not implemented. /// - **Windows**: @@ -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 f4a48c168..290730067 100644 --- a/crates/tauri/src/webview/webview_window.rs +++ b/crates/tauri/src/webview/webview_window.rs @@ -465,28 +465,28 @@ impl<'a, R: Runtime, M: Manager> WebviewWindowBuilder<'a, R, M> { self } - /// The initial position of the window's. + /// The initial position of the window in logical pixels. #[must_use] pub fn position(mut self, x: f64, y: f64) -> Self { self.window_builder = self.window_builder.position(x, y); self } - /// Window size. + /// Window size in logical pixels. #[must_use] pub fn inner_size(mut self, width: f64, height: f64) -> Self { self.window_builder = self.window_builder.inner_size(width, height); self } - /// Window min inner size. + /// Window min inner size in logical pixels. #[must_use] pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { self.window_builder = self.window_builder.min_inner_size(min_width, min_height); self } - /// Window max inner size. + /// Window max inner size in logical pixels. #[must_use] pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { self.window_builder = self.window_builder.max_inner_size(max_width, max_height); @@ -1230,7 +1230,7 @@ impl> WebviewWindowBuilder<'_, R, M> { self } - /// Allows overriding the the keyboard accessory view on iOS. + /// Allows overriding the keyboard accessory view on iOS. /// Returning `None` effectively removes the view. /// /// The closure parameter is the webview instance. @@ -2042,9 +2042,9 @@ impl WebviewWindow { /// Sets this window's minimum inner width. pub fn set_size_constraints( &self, - constriants: tauri_runtime::window::WindowSizeConstraints, + constraints: tauri_runtime::window::WindowSizeConstraints, ) -> crate::Result<()> { - self.window.set_size_constraints(constriants) + self.window.set_size_constraints(constraints) } /// Sets this window's position. @@ -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 92a515237..47c95628b 100644 --- a/crates/tauri/src/window/mod.rs +++ b/crates/tauri/src/window/mod.rs @@ -443,28 +443,28 @@ impl<'a, R: Runtime, M: Manager> WindowBuilder<'a, R, M> { self } - /// The initial position of the window's. + /// The initial position of the window in logical pixels. #[must_use] pub fn position(mut self, x: f64, y: f64) -> Self { self.window_builder = self.window_builder.position(x, y); self } - /// Window size. + /// Window size in logical pixels. #[must_use] pub fn inner_size(mut self, width: f64, height: f64) -> Self { self.window_builder = self.window_builder.inner_size(width, height); self } - /// Window min inner size. + /// Window min inner size in logical pixels. #[must_use] pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { self.window_builder = self.window_builder.min_inner_size(min_width, min_height); self } - /// Window max inner size. + /// Window max inner size in logical pixels. #[must_use] pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { self.window_builder = self.window_builder.max_inner_size(max_width, max_height); @@ -1941,12 +1941,12 @@ tauri::Builder::default() /// Sets this window's minimum inner width. pub fn set_size_constraints( &self, - constriants: tauri_runtime::window::WindowSizeConstraints, + constraints: tauri_runtime::window::WindowSizeConstraints, ) -> crate::Result<()> { self .window .dispatcher - .set_size_constraints(constriants) + .set_size_constraints(constraints) .map_err(Into::into) } @@ -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/crates/tauri/src/window/scripts/drag.js b/crates/tauri/src/window/scripts/drag.js index 21aa05697..1c9461b63 100644 --- a/crates/tauri/src/window/scripts/drag.js +++ b/crates/tauri/src/window/scripts/drag.js @@ -30,7 +30,7 @@ ) { // macOS maximization happens on `mouseup`, // so we save needed state and early return - if (osName === 'macos' && e.detail == 2) { + if (osName === 'macos' && e.detail === 2) { initialX = e.clientX initialY = e.clientY return @@ -48,7 +48,7 @@ window.__TAURI_INTERNALS__.invoke('plugin:window|' + cmd) } }) - // on macOS we maximze on mouseup instead, to match the system behavior where maximization can be canceled + // on macOS we maximize on mouseup instead, to match the system behavior where maximization can be canceled // if the mouse moves outside the data-tauri-drag-region if (osName === 'macos') { document.addEventListener('mouseup', (e) => { diff --git a/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json b/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json index 26355eed5..78ec36d96 100644 --- a/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json +++ b/crates/tests/acl/fixtures/capabilities/scope-extended/cap.json @@ -25,12 +25,12 @@ "identifier": "fs:allow-app", "allow": [ { - "path": "$APP/**" + "path": "$APPDATA/**" } ], "deny": [ { - "path": "$APP/*.db" + "path": "$APPDATA/*.db" } ] }, diff --git a/crates/tests/acl/fixtures/plugins/fs/scope.toml b/crates/tests/acl/fixtures/plugins/fs/scope.toml index 6d8a29a3f..efe82a96c 100644 --- a/crates/tests/acl/fixtures/plugins/fs/scope.toml +++ b/crates/tests/acl/fixtures/plugins/fs/scope.toml @@ -1,8 +1,8 @@ [[permission]] identifier = "allow-app" -description = "Allows accessing the $APP path." +description = "Allows accessing the $APPDATA path." [[permission.scope.allow]] -path = "$APP" +path = "$APPDATA" [[permission]] identifier = "allow-download-dir" diff --git a/crates/tests/acl/fixtures/plugins/os/windows.toml b/crates/tests/acl/fixtures/plugins/os/windows.toml index 577b0c967..1f84a6d99 100644 --- a/crates/tests/acl/fixtures/plugins/os/windows.toml +++ b/crates/tests/acl/fixtures/plugins/os/windows.toml @@ -3,4 +3,4 @@ identifier = "deny-webview-folder-windows" platforms = ["windows"] description = "Denies access to the webview folder on Windows" [[permission.scope.deny]] -path = "$APP/EBWebView/**" +path = "$APPLOCALDATA/EBWebView/**" diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap index dd9b05093..50029e7bd 100644 --- a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer-remote.snap @@ -398,7 +398,7 @@ Resolved { Map( { "path": String( - "$APP", + "$APPDATA", ), }, ), diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap index a3e4cd8b3..03f795b43 100644 --- a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__file-explorer.snap @@ -68,7 +68,7 @@ Resolved { Map( { "path": String( - "$APP", + "$APPDATA", ), }, ), diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap index f80ef7566..95ba3490d 100644 --- a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__multiwindow.snap @@ -310,7 +310,7 @@ Resolved { Map( { "path": String( - "$APP", + "$APPDATA", ), }, ), diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap index 41d2d99d7..7f1606fae 100644 --- a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope-extended.snap @@ -244,14 +244,14 @@ Resolved { Map( { "path": String( - "$APP/**", + "$APPDATA/**", ), }, ), Map( { "path": String( - "$APP", + "$APPDATA", ), }, ), @@ -281,7 +281,7 @@ Resolved { Map( { "path": String( - "$APP/*.db", + "$APPDATA/*.db", ), }, ), diff --git a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap index e98810961..b74d04381 100644 --- a/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap +++ b/crates/tests/acl/fixtures/snapshots/acl_tests__tests__scope.snap @@ -208,7 +208,7 @@ Resolved { Map( { "path": String( - "$APP", + "$APPDATA", ), }, ), diff --git a/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap b/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap index 618dcd1a7..3c1197d81 100644 --- a/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap +++ b/crates/tests/acl/fixtures/snapshots/windows/acl_tests__tests__platform-specific-permissions.snap @@ -3,6 +3,7 @@ source: crates/tests/acl/src/lib.rs expression: resolved --- Resolved { + has_app_acl: false, allowed_commands: { "plugin:os|spawn": [ ResolvedCommand { @@ -56,7 +57,7 @@ Resolved { Map( { "path": String( - "$APP/EBWebView/**", + "$APPLOCALDATA/EBWebView/**", ), }, ), diff --git a/examples/api/package.json b/examples/api/package.json index 9aa081b90..65ede4686 100644 --- a/examples/api/package.json +++ b/examples/api/package.json @@ -19,6 +19,6 @@ "@unocss/extractor-svelte": "^66.3.3", "svelte": "^5.35.6", "unocss": "^66.3.3", - "vite": "^7.1.5" + "vite": "^7.1.11" } } diff --git a/examples/api/unocss.config.js b/examples/api/unocss.config.js index 6e379c5a1..c1665d25a 100644 --- a/examples/api/unocss.config.js +++ b/examples/api/unocss.config.js @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -import { defineConfig, presetIcons, presetUno, presetWebFonts } from 'unocss' +import { defineConfig, presetIcons, presetWind3, presetWebFonts } from 'unocss' import extractorSvelte from '@unocss/extractor-svelte' export default defineConfig({ @@ -88,7 +88,7 @@ export default defineConfig({ checkbox: 'accent-accent' }, presets: [ - presetUno(), + presetWind3(), presetIcons(), presetWebFonts({ fonts: { diff --git a/examples/file-associations/src-tauri/src/main.rs b/examples/file-associations/src-tauri/src/main.rs index caf6affeb..c2c631e24 100644 --- a/examples/file-associations/src-tauri/src/main.rs +++ b/examples/file-associations/src-tauri/src/main.rs @@ -56,7 +56,7 @@ fn main() { // NOTICE: `args` may include URL protocol (`your-app-protocol://`) // or arguments (`--`) if your app supports them. - // files may aslo be passed as `file://path/to/file` + // files may also be passed as `file://path/to/file` for maybe_file in std::env::args().skip(1) { // skip flags like -f or --flag if maybe_file.starts_with('-') { diff --git a/package.json b/package.json index d70a5e171..5422c5a7f 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "example:api:dev": "pnpm run --filter \"api\" tauri dev" }, "devDependencies": { - "prettier": "^3.5.3" + "prettier": "^3.6.2" }, "minimumReleaseAge": 4320, "packageManager": "pnpm@10.16.0", diff --git a/packages/api/CHANGELOG.md b/packages/api/CHANGELOG.md index 6d256dec1..f9cce7cdf 100644 --- a/packages/api/CHANGELOG.md +++ b/packages/api/CHANGELOG.md @@ -1,5 +1,26 @@ # Changelog +## \[2.9.1] + +### Bug Fixes + +- [`ad1dec2e2`](https://www.github.com/tauri-apps/tauri/commit/ad1dec2e2488fe5c0a004b69f1bd290dfc593bf8) ([#14464](https://www.github.com/tauri-apps/tauri/pull/14464) by [@funnydino](https://www.github.com/tauri-apps/tauri/../../funnydino)) Fix `addPluginListener` fallback added in https://github.com/tauri-apps/tauri/pull/14132 didn't work properly + +## \[2.9.0] + +### New Features + +- [`f5851ee00`](https://www.github.com/tauri-apps/tauri/commit/f5851ee00d6d1f4d560a220ca5a728fedd525092) ([#14089](https://www.github.com/tauri-apps/tauri/pull/14089)) Adds the `scrollBarStyle` option to the Webview and WebviewBuilder constructors. +- [`3397fd9bf`](https://www.github.com/tauri-apps/tauri/commit/3397fd9bfe5f6b1337110149f6c34731b8a44bb3) ([#14133](https://www.github.com/tauri-apps/tauri/pull/14133)) Added `app > onBackButtonPress` for Android back button handling. + +### Enhancements + +- [`59089723f`](https://www.github.com/tauri-apps/tauri/commit/59089723fc20d66f3f305f2008adeb279bf87462) ([#14091](https://www.github.com/tauri-apps/tauri/pull/14091)) Added a config to set a data_directory relative to the app-specific data dir in JavaScript and `tauri.conf.json`. + +### Bug Fixes + +- [`08bda64c2`](https://www.github.com/tauri-apps/tauri/commit/08bda64c25008bd45c5b58d06ff14649081a2f5d) ([#14132](https://www.github.com/tauri-apps/tauri/pull/14132)) Fix `core > addPluginListener` failing on command permission check. + ## \[2.8.0] ### New Features diff --git a/packages/api/package.json b/packages/api/package.json index a75bcbffc..7c6899d72 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -1,6 +1,6 @@ { "name": "@tauri-apps/api", - "version": "2.8.0", + "version": "2.9.1", "description": "Tauri API definitions", "funding": { "type": "opencollective", @@ -47,15 +47,15 @@ "devDependencies": { "@eslint/js": "^9.29.0", "@rollup/plugin-terser": "0.4.4", - "@rollup/plugin-typescript": "12.1.4", + "@rollup/plugin-typescript": "12.3.0", "@types/eslint": "^9.6.1", - "@types/node": "^22.15.32", + "@types/node": "^24.0.0", "eslint": "^9.29.0", "eslint-config-prettier": "10.1.8", "eslint-plugin-security": "3.0.1", "fast-glob": "3.3.3", - "globals": "^16.2.0", - "rollup": "4.52.4", + "globals": "^17.0.0", + "rollup": "4.55.2", "tslib": "^2.8.1", "typescript": "^5.8.3", "typescript-eslint": "^8.34.1" diff --git a/packages/api/src/app.ts b/packages/api/src/app.ts index 55b0f3e2f..55b280436 100644 --- a/packages/api/src/app.ts +++ b/packages/api/src/app.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: MIT -import { invoke } from './core' +import { addPluginListener, invoke, PluginListener } from './core' import { Image } from './image' import { Theme } from './window' @@ -252,6 +252,28 @@ async function getBundleType(): Promise { return invoke('plugin:app|bundle_type') } +/** + * Payload for the onBackButtonPress event. + */ +type OnBackButtonPressPayload = { + /** Whether the webview canGoBack property is true. */ + canGoBack: boolean +} + +/** + * Listens to the backButton event on Android. + * @param handler + */ +async function onBackButtonPress( + handler: (payload: OnBackButtonPressPayload) => void +): Promise { + return addPluginListener( + 'app', + 'back-button', + handler + ) +} + export { getName, getVersion, @@ -264,5 +286,7 @@ export { fetchDataStoreIdentifiers, removeDataStore, setDockVisibility, - getBundleType + getBundleType, + type OnBackButtonPressPayload, + onBackButtonPress } diff --git a/packages/api/src/core.ts b/packages/api/src/core.ts index d3a91edb4..5e928516d 100644 --- a/packages/api/src/core.ts +++ b/packages/api/src/core.ts @@ -186,16 +186,16 @@ async function addPluginListener( ): Promise { const handler = new Channel(cb) try { - return invoke(`plugin:${plugin}|register_listener`, { + await invoke(`plugin:${plugin}|register_listener`, { event, handler - }).then(() => new PluginListener(plugin, event, handler.id)) + }) + return new PluginListener(plugin, event, handler.id) } catch { // TODO(v3): remove this fallback // note: we must try with camelCase here for backwards compatibility - return invoke(`plugin:${plugin}|registerListener`, { event, handler }).then( - () => new PluginListener(plugin, event, handler.id) - ) + await invoke(`plugin:${plugin}|registerListener`, { event, handler }) + return new PluginListener(plugin, event, handler.id) } } @@ -294,7 +294,7 @@ function convertFileSrc(filePath: string, protocol = 'asset'): string { * A rust-backed resource stored through `tauri::Manager::resources_table` API. * * The resource lives in the main process and does not exist - * in the Javascript world, and thus will not be cleaned up automatiacally + * in the Javascript world, and thus will not be cleaned up automatically * except on application exit. If you want to clean it up early, call {@linkcode Resource.close} * * @example diff --git a/packages/api/src/dpi.ts b/packages/api/src/dpi.ts index 88409726b..0a40d67d0 100644 --- a/packages/api/src/dpi.ts +++ b/packages/api/src/dpi.ts @@ -78,7 +78,7 @@ class LogicalSize { * * Physical pixels represent actual screen pixels, and are DPI-independent. * For high-DPI windows, this means that any point in the window on the screen - * will have a different position in logical pixels (@linkcode LogicalSize). + * will have a different position in logical pixels {@linkcode LogicalSize}. * * For physical-pixel-based position, see {@linkcode PhysicalPosition}. * diff --git a/packages/api/src/webview.ts b/packages/api/src/webview.ts index cf78dffe6..47a497fb6 100644 --- a/packages/api/src/webview.ts +++ b/packages/api/src/webview.ts @@ -714,13 +714,13 @@ interface WebviewOptions { * - local file path or route such as `/path/to/page.html` or `/users` is appended to the application URL (the devServer URL on development, or `tauri://localhost/` and `https://tauri.localhost/` on production). */ url?: string - /** The initial vertical position. */ + /** The initial vertical position in logical pixels. */ x: number - /** The initial horizontal position. */ + /** The initial horizontal position in logical pixels. */ y: number - /** The initial width. */ + /** The initial width in logical pixels. */ width: number - /** The initial height. */ + /** The initial height in logical pixels. */ height: number /** * Whether the webview is transparent or not. diff --git a/packages/api/src/webviewWindow.ts b/packages/api/src/webviewWindow.ts index f73d5cab5..ed1ebcfe9 100644 --- a/packages/api/src/webviewWindow.ts +++ b/packages/api/src/webviewWindow.ts @@ -102,8 +102,8 @@ class WebviewWindow { * Gets the Webview for the webview associated with the given label. * @example * ```typescript - * import { Webview } from '@tauri-apps/api/webviewWindow'; - * const mainWebview = Webview.getByLabel('main'); + * import { WebviewWindow } from '@tauri-apps/api/webviewWindow'; + * const mainWebview = WebviewWindow.getByLabel('main'); * ``` * * @param label The webview label. @@ -134,7 +134,7 @@ class WebviewWindow { } /** - * Listen to an emitted event on this webivew window. + * Listen to an emitted event on this webview window. * * @example * ```typescript diff --git a/packages/api/src/window.ts b/packages/api/src/window.ts index e89a8ae6c..8a11d2cc3 100644 --- a/packages/api/src/window.ts +++ b/packages/api/src/window.ts @@ -2229,7 +2229,7 @@ enum Effect { */ Acrylic = 'acrylic', /** - * Tabbed effect that matches the system dark perefence **Windows 11 Only** + * Tabbed effect that matches the system dark preference **Windows 11 Only** */ Tabbed = 'tabbed', /** @@ -2305,21 +2305,21 @@ interface PreventOverflowMargin { interface WindowOptions { /** Show window in the center of the screen.. */ center?: boolean - /** The initial vertical position. Only applies if `y` is also set. */ + /** The initial vertical position in logical pixels. Only applies if `y` is also set. */ x?: number - /** The initial horizontal position. Only applies if `x` is also set. */ + /** The initial horizontal position in logical pixels. Only applies if `x` is also set. */ y?: number - /** The initial width. */ + /** The initial width in logical pixels. */ width?: number - /** The initial height. */ + /** The initial height in logical pixels. */ height?: number - /** The minimum width. Only applies if `minHeight` is also set. */ + /** The minimum width in logical pixels. Only applies if `minHeight` is also set. */ minWidth?: number - /** The minimum height. Only applies if `minWidth` is also set. */ + /** The minimum height in logical pixels. Only applies if `minWidth` is also set. */ minHeight?: number - /** The maximum width. Only applies if `maxHeight` is also set. */ + /** The maximum width in logical pixels. Only applies if `maxHeight` is also set. */ maxWidth?: number - /** The maximum height. Only applies if `maxWidth` is also set. */ + /** The maximum height in logical pixels. Only applies if `maxWidth` is also set. */ maxHeight?: number /** * Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) diff --git a/packages/cli/CHANGELOG.md b/packages/cli/CHANGELOG.md index 642a5043b..305a65a38 100644 --- a/packages/cli/CHANGELOG.md +++ b/packages/cli/CHANGELOG.md @@ -1,5 +1,92 @@ # Changelog +## \[2.9.6] + +### Dependencies + +- Upgraded to `tauri-cli@2.9.6` + +## \[2.9.5] + +### Bug Fixes + +- [`f855caf8a`](https://www.github.com/tauri-apps/tauri/commit/f855caf8a3830aa5dd6d0b039312866a5d9c3606) ([#14481](https://www.github.com/tauri-apps/tauri/pull/14481) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Fixed the mismatched tauri package versions check didn't work for pnpm + +### Performance Improvements + +- [`ce98d87ce`](https://www.github.com/tauri-apps/tauri/commit/ce98d87ce0aaa907285852eb80691197424e03c3) ([#14474](https://www.github.com/tauri-apps/tauri/pull/14474) by [@Tunglies](https://www.github.com/tauri-apps/tauri/../../Tunglies)) refactor: remove needless collect. No user facing changes. + +### Dependencies + +- Upgraded to `tauri-cli@2.9.5` + +## \[2.9.4] + +### Bug Fixes + +- [`b586ecf1f`](https://www.github.com/tauri-apps/tauri/commit/b586ecf1f4b3b087f9aa6c4668c2c18b1b7925f4) ([#14416](https://www.github.com/tauri-apps/tauri/pull/14416) by [@Legend-Master](https://www.github.com/tauri-apps/tauri/../../Legend-Master)) Premultiply Alpha before Resizing which gets rid of the gray fringe around the icons for svg images. + +### Dependencies + +- Upgraded to `tauri-cli@2.9.4` + +## \[2.9.3] + +### Bug Fixes + +- [`fd8c30b4f`](https://www.github.com/tauri-apps/tauri/commit/fd8c30b4f1bca8dd7165c5c0ebe7fbfd17662153) ([#14353](https://www.github.com/tauri-apps/tauri/pull/14353) by [@ChaseKnowlden](https://www.github.com/tauri-apps/tauri/../../ChaseKnowlden)) Premultiply Alpha before Resizing which gets rid of the gray fringe around the icons. + +### Dependencies + +- Upgraded to `tauri-cli@2.9.3` + +## \[2.9.2] + +### Dependencies + +- Upgraded to `tauri-cli@2.9.2` + +## \[2.9.1] + +### Dependencies + +- Upgraded to `tauri-cli@2.9.1` + +## \[2.9.0] + +### New Features + +- [`3b4fac201`](https://www.github.com/tauri-apps/tauri/commit/3b4fac2017832d426dd07c5e24e26684eda57f7b) ([#14194](https://www.github.com/tauri-apps/tauri/pull/14194)) Add `tauri.conf.json > bundle > android > autoIncrementVersionCode` config option to automatically increment the Android version code. +- [`673867aa0`](https://www.github.com/tauri-apps/tauri/commit/673867aa0e1ccd766ee879ffe96aba58c758613c) ([#14094](https://www.github.com/tauri-apps/tauri/pull/14094)) Try to detect ANDROID_HOME and NDK_HOME environment variables from default system locations and install them if needed using the Android Studio command line tools. +- [`3d6868d09`](https://www.github.com/tauri-apps/tauri/commit/3d6868d09c323d68a152f3c3f8c7256311bd020a) ([#14128](https://www.github.com/tauri-apps/tauri/pull/14128)) Added support to defining the content type of the declared file association on macOS (maps to LSItemContentTypes property). +- [`3d6868d09`](https://www.github.com/tauri-apps/tauri/commit/3d6868d09c323d68a152f3c3f8c7256311bd020a) ([#14128](https://www.github.com/tauri-apps/tauri/pull/14128)) Added support to defining the metadata for custom types declared in `tauri.conf.json > bundle > fileAssociations > exportedType` via the `UTExportedTypeDeclarations` Info.plist property. +- [`ed7c9a410`](https://www.github.com/tauri-apps/tauri/commit/ed7c9a4100e08c002212265549d12130d021ad1e) ([#14108](https://www.github.com/tauri-apps/tauri/pull/14108)) Added `bundle > macOS > infoPlist` and `bundle > iOS > infoPlist` configurations to allow defining custom Info.plist extensions. +- [`75082cc5b`](https://www.github.com/tauri-apps/tauri/commit/75082cc5b340e30e2c4b4cd4bd6a1fe5382164aa) ([#14120](https://www.github.com/tauri-apps/tauri/pull/14120)) Added `ios run` and `android run` commands to run the app in production mode. +- [`cc8c0b531`](https://www.github.com/tauri-apps/tauri/commit/cc8c0b53171173dbd1d01781a50de1a3ea159031) ([#14031](https://www.github.com/tauri-apps/tauri/pull/14031)) Added support to universal app links on macOS with the `plugins > deep-link > desktop > domains` configuration. + +### Enhancements + +- [`b5aa01870`](https://www.github.com/tauri-apps/tauri/commit/b5aa018702bf45dc98297698f9b7d238705865a6) ([#14268](https://www.github.com/tauri-apps/tauri/pull/14268)) Update cargo-mobile2 to 0.21, enhancing error messages and opening Xcode when multiple apps are installed. +- [`55453e845`](https://www.github.com/tauri-apps/tauri/commit/55453e8453d927b8197f1ba9f26fd944482938f7) ([#14262](https://www.github.com/tauri-apps/tauri/pull/14262)) Check mismatched versions in `tauri info` +- [`1a6627ee7`](https://www.github.com/tauri-apps/tauri/commit/1a6627ee7d085a4e66784e2705254714d68c7244) ([#14122](https://www.github.com/tauri-apps/tauri/pull/14122)) Set a default log level filter when running `tauri add log`. +- [`b06b3bd09`](https://www.github.com/tauri-apps/tauri/commit/b06b3bd091b0fed26cdcfb23cacb0462a7a9cc2d) ([#14126](https://www.github.com/tauri-apps/tauri/pull/14126)) Improve error messages with more context. +- [`f6622a3e3`](https://www.github.com/tauri-apps/tauri/commit/f6622a3e342f5dd5fb3cf6e0f79fb309a10e9b3d) ([#14129](https://www.github.com/tauri-apps/tauri/pull/14129)) Prompt to install the iOS platform if it isn't installed yet. +- [`6bbb530fd`](https://www.github.com/tauri-apps/tauri/commit/6bbb530fd5edfc07b180a4f3782b8566872ca3b1) ([#14105](https://www.github.com/tauri-apps/tauri/pull/14105)) Warn if productName is empty when initializing mobile project. + +### Bug Fixes + +- [`19fb6f7cb`](https://www.github.com/tauri-apps/tauri/commit/19fb6f7cb0d702cb2f25f6f2d1e11014d9dada5d) ([#14146](https://www.github.com/tauri-apps/tauri/pull/14146)) Strip Windows-only extensions from the binary path so an Android project initialized on Windows can be used on UNIX systems. +- [`19fb6f7cb`](https://www.github.com/tauri-apps/tauri/commit/19fb6f7cb0d702cb2f25f6f2d1e11014d9dada5d) ([#14146](https://www.github.com/tauri-apps/tauri/pull/14146)) Enhance Android build script usage on Windows by attempting to run cmd, bat and exe formats. +- [`28a2f9bc5`](https://www.github.com/tauri-apps/tauri/commit/28a2f9bc55f658eb71ef1a970ff9f791346f7682) ([#14101](https://www.github.com/tauri-apps/tauri/pull/14101)) Fix iOS CLI usage after modifying the package name. +- [`d2938486e`](https://www.github.com/tauri-apps/tauri/commit/d2938486e9d974debd90c15d7160b8a17bf4d763) ([#14261](https://www.github.com/tauri-apps/tauri/pull/14261)) Replaced the non-standard nerd font character with ` ⱼₛ ` in `tarui info` +- [`25e920e16`](https://www.github.com/tauri-apps/tauri/commit/25e920e169db900ca4f07c2bb9eb290e9f9f2c7d) ([#14298](https://www.github.com/tauri-apps/tauri/pull/14298)) Wait for dev server to exit before exiting the CLI when the app is closed on `tauri dev --no-watch`. +- [`b0012424c`](https://www.github.com/tauri-apps/tauri/commit/b0012424c5f432debfa42ba145e2672966d5f6d5) ([#14115](https://www.github.com/tauri-apps/tauri/pull/14115)) Resolve local IP address when `tauri.conf.json > build > devUrl` host is `0.0.0.0`. +- [`abf7e8850`](https://www.github.com/tauri-apps/tauri/commit/abf7e8850ba41e7173e9e9a3fdd6dfb8f357d72d) ([#14118](https://www.github.com/tauri-apps/tauri/pull/14118)) Fixes mobile project initialization when using `pnpx` or `pnpm dlx`. + +### Dependencies + +- Upgraded to `tauri-cli@2.9.0` + ## \[2.8.4] ### Enhancements diff --git a/packages/cli/package.json b/packages/cli/package.json index 8fd5434f3..f6dce72a9 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "@tauri-apps/cli", - "version": "2.8.4", + "version": "2.9.6", "description": "Command line interface for building Tauri apps", "type": "commonjs", "funding": { @@ -41,10 +41,10 @@ ] }, "devDependencies": { - "@napi-rs/cli": "^3.0.0", - "@types/node": "^22.15.32", + "@napi-rs/cli": "^3.4.1", + "@types/node": "^24.0.0", "cross-env": "10.1.0", - "vitest": "^3.2.4" + "vitest": "^4.0.0" }, "engines": { "node": ">= 10" 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 9a8167155..b99d7cc26 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,14 +15,14 @@ importers: .: devDependencies: prettier: - specifier: ^3.5.3 - version: 3.5.3 + specifier: ^3.6.2 + version: 3.6.2 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: @@ -38,7 +38,7 @@ importers: version: 1.2.2 '@sveltejs/vite-plugin-svelte': specifier: ^6.0.0 - version: 6.0.0(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)) + version: 6.0.0(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)) '@unocss/extractor-svelte': specifier: ^66.3.3 version: 66.3.3 @@ -47,10 +47,10 @@ importers: version: 5.35.6 unocss: specifier: ^66.3.3 - version: 66.3.3(postcss@8.5.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) + version: 66.3.3(postcss@8.5.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) vite: - specifier: ^7.1.5 - version: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + specifier: ^7.1.11 + version: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) examples/file-associations: {} @@ -63,16 +63,16 @@ importers: version: 9.29.0 '@rollup/plugin-terser': specifier: 0.4.4 - version: 0.4.4(rollup@4.52.4) + version: 0.4.4(rollup@4.55.2) '@rollup/plugin-typescript': - specifier: 12.1.4 - version: 12.1.4(rollup@4.52.4)(tslib@2.8.1)(typescript@5.8.3) + specifier: 12.3.0 + 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 '@types/node': - specifier: ^22.15.32 - version: 22.15.32 + specifier: ^24.0.0 + version: 24.10.0 eslint: specifier: ^9.29.0 version: 9.29.0(jiti@2.4.2) @@ -86,11 +86,11 @@ importers: specifier: 3.3.3 version: 3.3.3 globals: - specifier: ^16.2.0 - version: 16.2.0 + specifier: ^17.0.0 + version: 17.0.0 rollup: - specifier: 4.52.4 - version: 4.52.4 + specifier: 4.55.2 + version: 4.55.2 tslib: specifier: ^2.8.1 version: 2.8.1 @@ -104,17 +104,17 @@ importers: packages/cli: devDependencies: '@napi-rs/cli': - specifier: ^3.0.0 - version: 3.0.0(@emnapi/runtime@1.4.3)(@types/node@22.15.32) + specifier: ^3.4.1 + version: 3.4.1(@emnapi/runtime@1.8.1)(@types/node@24.10.0) '@types/node': - specifier: ^22.15.32 - version: 22.15.32 + specifier: ^24.0.0 + version: 24.10.0 cross-env: specifier: 10.1.0 version: 10.1.0 vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + specifier: ^4.0.0 + version: 4.0.6(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) packages: @@ -132,58 +132,58 @@ packages: resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.4': - resolution: {integrity: sha512-yZbBqeM6TkpP9du/I2pUZnJsRMGGvOuIrhjzC1AwHwW+6he4mni6Bp/m8ijn0iOuZuPI2BfkCoSRunpyjnrQKg==} + '@babel/parser@7.28.6': + resolution: {integrity: sha512-TeR9zWR18BvbfPmGbLampPMW+uW1NZnJlRuuHso8i87QZNq2JRF9i6RgxRqtEq+wQGsS19NNTWr2duhnE49mfQ==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/types@7.28.4': - resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} + '@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] @@ -192,14 +192,14 @@ packages: resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@emnapi/core@1.4.5': - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - '@emnapi/runtime@1.4.3': - resolution: {integrity: sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==} + '@emnapi/runtime@1.8.1': + resolution: {integrity: sha512-mehfKSMWjjNol8659Z8KxEMrdSJDDot5SXMq00dM8BN4o+CLNXQ0xH2V7EchNHV4RmbZLmmPdEaXZc5H2FXmDg==} - '@emnapi/wasi-threads@1.0.4': - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} + '@emnapi/wasi-threads@1.1.0': + resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} '@epic-web/invariant@1.0.0': resolution: {integrity: sha512-lrTPqgvfFQtR/eY/qkIzp98OGdNJu0m5ji3q/nJI8v3SXkRKEnWiOxMmbvcSoAIzv/cGiuvRy57k4suKQSAdwA==} @@ -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,113 +584,149 @@ 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] - '@inquirer/checkbox@4.1.9': - resolution: {integrity: sha512-DBJBkzI5Wx4jFaYm221LHvAhpKYkhVS0k9plqHwaHhofGNxvYB7J3Bz8w+bFJ05zaMb0sZNHo4KdmENQFlNTuQ==} + '@inquirer/ansi@1.0.2': + resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} + engines: {node: '>=18'} + + '@inquirer/checkbox@4.3.2': + resolution: {integrity: sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -546,8 +734,8 @@ packages: '@types/node': optional: true - '@inquirer/confirm@5.1.13': - resolution: {integrity: sha512-EkCtvp67ICIVVzjsquUiVSd+V5HRGOGQfsqA4E4vMWhYnB7InUL0pa0TIWt1i+OfP16Gkds8CdIu6yGZwOM1Yw==} + '@inquirer/confirm@5.1.21': + resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -555,8 +743,8 @@ packages: '@types/node': optional: true - '@inquirer/core@10.1.14': - resolution: {integrity: sha512-Ma+ZpOJPewtIYl6HZHZckeX1STvDnHTCB2GVINNUlSEn2Am6LddWwfPkIGY0IUFVjUUrr/93XlBwTK6mfLjf0A==} + '@inquirer/core@10.3.2': + resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -564,8 +752,8 @@ packages: '@types/node': optional: true - '@inquirer/editor@4.2.14': - resolution: {integrity: sha512-yd2qtLl4QIIax9DTMZ1ZN2pFrrj+yL3kgIWxm34SS6uwCr0sIhsNyudUjAo5q3TqI03xx4SEBkUJqZuAInp9uA==} + '@inquirer/editor@4.2.23': + resolution: {integrity: sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -573,8 +761,8 @@ packages: '@types/node': optional: true - '@inquirer/expand@4.0.16': - resolution: {integrity: sha512-oiDqafWzMtofeJyyGkb1CTPaxUkjIcSxePHHQCfif8t3HV9pHcw1Kgdw3/uGpDvaFfeTluwQtWiqzPVjAqS3zA==} + '@inquirer/expand@4.0.23': + resolution: {integrity: sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -582,12 +770,8 @@ packages: '@types/node': optional: true - '@inquirer/figures@1.0.12': - resolution: {integrity: sha512-MJttijd8rMFcKJC8NYmprWr6hD3r9Gd9qUC0XwPNwoEPWSMVJwA2MlXxF+nhZZNMY+HXsWa+o7KY2emWYIn0jQ==} - engines: {node: '>=18'} - - '@inquirer/input@4.2.0': - resolution: {integrity: sha512-opqpHPB1NjAmDISi3uvZOTrjEEU5CWVu/HBkDby8t93+6UxYX0Z7Ps0Ltjm5sZiEbWenjubwUkivAEYQmy9xHw==} + '@inquirer/external-editor@1.0.3': + resolution: {integrity: sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -595,8 +779,12 @@ packages: '@types/node': optional: true - '@inquirer/number@3.0.16': - resolution: {integrity: sha512-kMrXAaKGavBEoBYUCgualbwA9jWUx2TjMA46ek+pEKy38+LFpL9QHlTd8PO2kWPUgI/KB+qi02o4y2rwXbzr3Q==} + '@inquirer/figures@1.0.15': + resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + engines: {node: '>=18'} + + '@inquirer/input@4.3.1': + resolution: {integrity: sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -604,8 +792,8 @@ packages: '@types/node': optional: true - '@inquirer/password@4.0.16': - resolution: {integrity: sha512-g8BVNBj5Zeb5/Y3cSN+hDUL7CsIFDIuVxb9EPty3lkxBaYpjL5BNRKSYOF9yOLe+JOcKFd+TSVeADQ4iSY7rbg==} + '@inquirer/number@3.0.23': + resolution: {integrity: sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -613,8 +801,8 @@ packages: '@types/node': optional: true - '@inquirer/prompts@7.6.0': - resolution: {integrity: sha512-jAhL7tyMxB3Gfwn4HIJ0yuJ5pvcB5maYUcouGcgd/ub79f9MqZ+aVnBtuFf+VC2GTkCBF+R+eo7Vi63w5VZlzw==} + '@inquirer/password@4.0.23': + resolution: {integrity: sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -622,8 +810,8 @@ packages: '@types/node': optional: true - '@inquirer/rawlist@4.1.4': - resolution: {integrity: sha512-5GGvxVpXXMmfZNtvWw4IsHpR7RzqAR624xtkPd1NxxlV5M+pShMqzL4oRddRkg8rVEOK9fKdJp1jjVML2Lr7TQ==} + '@inquirer/prompts@7.10.1': + resolution: {integrity: sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -631,8 +819,8 @@ packages: '@types/node': optional: true - '@inquirer/search@3.0.16': - resolution: {integrity: sha512-POCmXo+j97kTGU6aeRjsPyuCpQQfKcMXdeTMw708ZMtWrj5aykZvlUxH4Qgz3+Y1L/cAVZsSpA+UgZCu2GMOMg==} + '@inquirer/rawlist@4.1.11': + resolution: {integrity: sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -640,8 +828,8 @@ packages: '@types/node': optional: true - '@inquirer/select@4.2.4': - resolution: {integrity: sha512-unTppUcTjmnbl/q+h8XeQDhAqIOmwWYWNyiiP2e3orXrg6tOaa5DHXja9PChCSbChOsktyKgOieRZFnajzxoBg==} + '@inquirer/search@3.2.2': + resolution: {integrity: sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -649,8 +837,17 @@ packages: '@types/node': optional: true - '@inquirer/type@3.0.7': - resolution: {integrity: sha512-PfunHQcjwnju84L+ycmcMKB/pTPIngjUJvfnRhKY6FKPuYXlM4aQCb/nIdTFR6BEhMjFvngzvng/vBAJMZpLSA==} + '@inquirer/select@4.4.2': + resolution: {integrity: sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==} + engines: {node: '>=18'} + peerDependencies: + '@types/node': '>=18' + peerDependenciesMeta: + '@types/node': + optional: true + + '@inquirer/type@3.0.10': + resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} engines: {node: '>=18'} peerDependencies: '@types/node': '>=18' @@ -677,328 +874,337 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@napi-rs/cli@3.0.0': - resolution: {integrity: sha512-V4xSbP4AnS+1POtAGVRhCt0erOTEyLAsZ2+MJOcI1NXCwgsKZGjp8cf/UmVo8e2jUE8tTkyxvnIPCqzVkT3RjQ==} + '@napi-rs/cli@3.4.1': + resolution: {integrity: sha512-ayhm+NfrP5Hmh7vy5pfyYm/ktYtLh2PrgdLuqHTAubO7RoO2JkUE4F991AtgYxNewwXI8+guZLxU8itV7QnDrQ==} engines: {node: '>= 16'} hasBin: true peerDependencies: - '@emnapi/runtime': ^1.1.0 - emnapi: ^1.1.0 + '@emnapi/runtime': ^1.5.0 peerDependenciesMeta: '@emnapi/runtime': optional: true - emnapi: - optional: true - '@napi-rs/cross-toolchain@0.0.19': - resolution: {integrity: sha512-StHXqYANdTaMFqJJ3JXHqKQMylOzOJPcrOCd9Nt2NIGfvfaXK3SzpmNfkJimkOAYfTsfpfuRERsML0bUZCpHBQ==} + '@napi-rs/cross-toolchain@1.0.3': + resolution: {integrity: sha512-ENPfLe4937bsKVTDA6zdABx4pq9w0tHqRrJHyaGxgaPq03a2Bd1unD5XSKjXJjebsABJ+MjAv1A2OvCgK9yehg==} peerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64': ^0.0.19 - '@napi-rs/cross-toolchain-arm64-target-armv7': ^0.0.19 - '@napi-rs/cross-toolchain-arm64-target-x86_64': ^0.0.19 - '@napi-rs/cross-toolchain-x64-target-aarch64': ^0.0.19 - '@napi-rs/cross-toolchain-x64-target-armv7': ^0.0.19 - '@napi-rs/cross-toolchain-x64-target-x86_64': ^0.0.19 + '@napi-rs/cross-toolchain-arm64-target-aarch64': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-armv7': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-ppc64le': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-s390x': ^1.0.3 + '@napi-rs/cross-toolchain-arm64-target-x86_64': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-aarch64': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-armv7': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-ppc64le': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-s390x': ^1.0.3 + '@napi-rs/cross-toolchain-x64-target-x86_64': ^1.0.3 peerDependenciesMeta: '@napi-rs/cross-toolchain-arm64-target-aarch64': optional: true '@napi-rs/cross-toolchain-arm64-target-armv7': optional: true + '@napi-rs/cross-toolchain-arm64-target-ppc64le': + optional: true + '@napi-rs/cross-toolchain-arm64-target-s390x': + optional: true '@napi-rs/cross-toolchain-arm64-target-x86_64': optional: true '@napi-rs/cross-toolchain-x64-target-aarch64': optional: true '@napi-rs/cross-toolchain-x64-target-armv7': optional: true + '@napi-rs/cross-toolchain-x64-target-ppc64le': + optional: true + '@napi-rs/cross-toolchain-x64-target-s390x': + optional: true '@napi-rs/cross-toolchain-x64-target-x86_64': optional: true - '@napi-rs/lzma-android-arm-eabi@1.4.3': - resolution: {integrity: sha512-XpjRUZ/EbWtVbMvW+ucon5Ykz7PjMoX65mIlUdAiVnaPGykzFAUrl8dl6Br5bfqnhQQfDjjUIgTAwWl3G++n1g==} + '@napi-rs/lzma-android-arm-eabi@1.4.5': + resolution: {integrity: sha512-Up4gpyw2SacmyKWWEib06GhiDdF+H+CCU0LAV8pnM4aJIDqKKd5LHSlBht83Jut6frkB0vwEPmAkv4NjQ5u//Q==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/lzma-android-arm64@1.4.3': - resolution: {integrity: sha512-Bve6BF/4pnlO6HotIgRWgmUT3rbbW/QH471RF/GBA29GfEeUOPEdfQWC7tlzrLYsVFNX2KCWKd+XlxQNz9sRaA==} + '@napi-rs/lzma-android-arm64@1.4.5': + resolution: {integrity: sha512-uwa8sLlWEzkAM0MWyoZJg0JTD3BkPknvejAFG2acUA1raXM8jLrqujWCdOStisXhqQjZ2nDMp3FV6cs//zjfuQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/lzma-darwin-arm64@1.4.3': - resolution: {integrity: sha512-UxTb56kL6pSVTsZ1ShibnqLSwJZLTWtPU5TNYuyIjVNQYAIG8JQ5Yxz35azjwBCK7AjD8pBdpWLYUSyJRGAVAw==} + '@napi-rs/lzma-darwin-arm64@1.4.5': + resolution: {integrity: sha512-0Y0TQLQ2xAjVabrMDem1NhIssOZzF/y/dqetc6OT8mD3xMTDtF8u5BqZoX3MyPc9FzpsZw4ksol+w7DsxHrpMA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/lzma-darwin-x64@1.4.3': - resolution: {integrity: sha512-ps6HiwGKS1P4ottyV2/hVboZ0ugdM1Z1qO9YFpcuKweORfxAkxwJ6S8jOt7G27LQiWiiQHVwsUCODTHDFhOUPQ==} + '@napi-rs/lzma-darwin-x64@1.4.5': + resolution: {integrity: sha512-vR2IUyJY3En+V1wJkwmbGWcYiT8pHloTAWdW4pG24+51GIq+intst6Uf6D/r46citObGZrlX0QvMarOkQeHWpw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/lzma-freebsd-x64@1.4.3': - resolution: {integrity: sha512-W49h41U3+vLnbthbPzvJX1fQtTG+1jyUlfB+wX3oxILvIur06PjJRdMXrFtOZpWkFsihK9gO2DRkQYQJIIgTZw==} + '@napi-rs/lzma-freebsd-x64@1.4.5': + resolution: {integrity: sha512-XpnYQC5SVovO35tF0xGkbHYjsS6kqyNCjuaLQ2dbEblFRr5cAZVvsJ/9h7zj/5FluJPJRDojVNxGyRhTp4z2lw==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': - resolution: {integrity: sha512-11PNPiMGuwwxIxd9yPZY3Ek6RFGFRFQb/AtMStJIwlmJ6sM/djEknClLJVbVXbC/nqm7htVZEr+qmYgoDy0fAw==} + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': + resolution: {integrity: sha512-ic1ZZMoRfRMwtSwxkyw4zIlbDZGC6davC9r+2oX6x9QiF247BRqqT94qGeL5ZP4Vtz0Hyy7TEViWhx5j6Bpzvw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/lzma-linux-arm64-gnu@1.4.3': - resolution: {integrity: sha512-XzlxZjSXTcrWFHbvvv2xbV5+bSV5IJqCJ8CCksc7xV3uWEAso9yBPJ8VSRD3GPc7ZoBDRqJmgCb/HQzHpLBekw==} + '@napi-rs/lzma-linux-arm64-gnu@1.4.5': + resolution: {integrity: sha512-asEp7FPd7C1Yi6DQb45a3KPHKOFBSfGuJWXcAd4/bL2Fjetb2n/KK2z14yfW8YC/Fv6x3rBM0VAZKmJuz4tysg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/lzma-linux-arm64-musl@1.4.3': - resolution: {integrity: sha512-k4fWiI4Pm61Esj8hnm7NWIbpZueTtP2jlJqmMhTqJyjqW3NUxbTHjSErZOZKIFRF1B3if4v5Tyzo7JL2X+BaSQ==} + '@napi-rs/lzma-linux-arm64-musl@1.4.5': + resolution: {integrity: sha512-yWjcPDgJ2nIL3KNvi4536dlT/CcCWO0DUyEOlBs/SacG7BeD6IjGh6yYzd3/X1Y3JItCbZoDoLUH8iB1lTXo3w==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': - resolution: {integrity: sha512-tTIfk+TYZYbFySxaCMuzp4Zz1T3I6OYVYNAm+IrCSkZDLmUKUzBK3+Su+mT+PjcTNsAiHBa5NVjARXC7b7jmgQ==} + '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': + resolution: {integrity: sha512-0XRhKuIU/9ZjT4WDIG/qnX7Xz7mSQHYZo9Gb3MP2gcvBgr6BA4zywQ9k3gmQaPn9ECE+CZg2V7DV7kT+x2pUMQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': - resolution: {integrity: sha512-HPyLYOYhkN7QYaWiKWhSnsLmx/l0pqgiiyaYeycgxCm9dwL8ummFWxveZqYjqdbUUvG7Mgi1jqgRe+55MVdyZQ==} + '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': + resolution: {integrity: sha512-QrqDIPEUUB23GCpyQj/QFyMlr8SGxxyExeZz9OWFnHfb70kXdTLWrHS/hEI1Ru+lSbQ/6xRqeoGyQ4Aqdg+/RA==} engines: {node: '>= 10'} cpu: [riscv64] os: [linux] - '@napi-rs/lzma-linux-s390x-gnu@1.4.3': - resolution: {integrity: sha512-YkcV+RSZZIMM3D5sPZqvo2Q7/tHXBhgJWBi+6ceo46pTlqgn/nH+pVz+CzsDmLWz5hqNSXyv5IAhOcg2CH6rAg==} + '@napi-rs/lzma-linux-s390x-gnu@1.4.5': + resolution: {integrity: sha512-k8RVM5aMhW86E9H0QXdquwojew4H3SwPxbRVbl49/COJQWCUjGi79X6mYruMnMPEznZinUiT1jgKbFo2A00NdA==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - '@napi-rs/lzma-linux-x64-gnu@1.4.3': - resolution: {integrity: sha512-ep6PLjN1+g4P12Hc7sLRmVpXXaHX22ykqxnOzjXUoj1KTph5XgM4+fUCyE5dsYI+lB4/tXqFuf9ZeFgHk5f00A==} + '@napi-rs/lzma-linux-x64-gnu@1.4.5': + resolution: {integrity: sha512-6rMtBgnIq2Wcl1rQdZsnM+rtCcVCbws1nF8S2NzaUsVaZv8bjrPiAa0lwg4Eqnn1d9lgwqT+cZgm5m+//K08Kw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/lzma-linux-x64-musl@1.4.3': - resolution: {integrity: sha512-QkCO6rVw0Z7eY0ziVc4aCFplbOTMpt0UBLPXWxsPd2lXtkAlRChzqaHOxdcL/HoLmBsqdCxmG0EZuHuAP/vKZQ==} + '@napi-rs/lzma-linux-x64-musl@1.4.5': + resolution: {integrity: sha512-eiadGBKi7Vd0bCArBUOO/qqRYPHt/VQVvGyYvDFt6C2ZSIjlD+HuOl+2oS1sjf4CFjK4eDIog6EdXnL0NE6iyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/lzma-wasm32-wasi@1.4.3': - resolution: {integrity: sha512-+rMamB0xaeDyVt4OP4cV888cnmso+m78iUebNhGcrL/WXIziwql50KQrmj7PBdBCza/W7XEcraZT8pO8gSDGcg==} + '@napi-rs/lzma-wasm32-wasi@1.4.5': + resolution: {integrity: sha512-+VyHHlr68dvey6fXc2hehw9gHVFIW3TtGF1XkcbAu65qVXsA9D/T+uuoRVqhE+JCyFHFrO0ixRbZDRK1XJt1sA==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/lzma-win32-arm64-msvc@1.4.3': - resolution: {integrity: sha512-6gQ+R6ztw11hswdsEu0jsOOXXnJPwhOA1yHRjqfuFemhf6esMd8l9b0uh3BfLBNe7qumtrH4KLrHu8yC9pSY3g==} + '@napi-rs/lzma-win32-arm64-msvc@1.4.5': + resolution: {integrity: sha512-eewnqvIyyhHi3KaZtBOJXohLvwwN27gfS2G/YDWdfHlbz1jrmfeHAmzMsP5qv8vGB+T80TMHNkro4kYjeh6Deg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/lzma-win32-ia32-msvc@1.4.3': - resolution: {integrity: sha512-+AJeJQoGE+QtZKlwM4VzDkfLmUa+6DsGOO5zdbIPlRCB6PEstRCXxp8lkMiQBNgk9f/IO0UEkRcJSZ+Hhqd8zw==} + '@napi-rs/lzma-win32-ia32-msvc@1.4.5': + resolution: {integrity: sha512-OeacFVRCJOKNU/a0ephUfYZ2Yt+NvaHze/4TgOwJ0J0P4P7X1mHzN+ig9Iyd74aQDXYqc7kaCXA2dpAOcH87Cg==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/lzma-win32-x64-msvc@1.4.3': - resolution: {integrity: sha512-66dFCX9ACpVUyTTom89nxhllc88yJyjxGFHO0M2olFcrSJArulfbE9kNIATgh04NDAe/l8VsDhnAxWuvJY1GuA==} + '@napi-rs/lzma-win32-x64-msvc@1.4.5': + resolution: {integrity: sha512-T4I1SamdSmtyZgDXGAGP+y5LEK5vxHUFwe8mz6D4R7Sa5/WCxTcCIgPJ9BD7RkpO17lzhlaM2vmVvMy96Lvk9Q==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/lzma@1.4.3': - resolution: {integrity: sha512-uBjLLoUM9ll03jL/bP7XjyPg0vTU0vQ35N1vVqQHbzlK/fVZyuF2B1p/A6kqPsFFhaoBKgO6oaxsuerv091RtQ==} + '@napi-rs/lzma@1.4.5': + resolution: {integrity: sha512-zS5LuN1OBPAyZpda2ZZgYOEDC+xecUdAGnrvbYzjnLXkrq/OBC3B9qcRvlxbDR3k5H/gVfvef1/jyUqPknqjbg==} engines: {node: '>= 10'} - '@napi-rs/tar-android-arm-eabi@0.1.5': - resolution: {integrity: sha512-FM2qNG3ELeYibnZC8dfsCV4i/pql1nlLKVINfRC7TSwqFfgj5gbezZ0rT8gRPHbLyslVt6m4MPZfRE8Uj/MuCA==} + '@napi-rs/tar-android-arm-eabi@1.1.0': + resolution: {integrity: sha512-h2Ryndraj/YiKgMV/r5by1cDusluYIRT0CaE0/PekQ4u+Wpy2iUVqvzVU98ZPnhXaNeYxEvVJHNGafpOfaD0TA==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/tar-android-arm64@0.1.5': - resolution: {integrity: sha512-OpP0QyD+K0a68nqyko793lLWiC2BN1wWF/Doatus1OCKxgj61vtrUPVO2cQGQS5i07I/+YGRF8lD0tQDrk4JDQ==} + '@napi-rs/tar-android-arm64@1.1.0': + resolution: {integrity: sha512-DJFyQHr1ZxNZorm/gzc1qBNLF/FcKzcH0V0Vwan5P+o0aE2keQIGEjJ09FudkF9v6uOuJjHCVDdK6S6uHtShAw==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/tar-darwin-arm64@0.1.5': - resolution: {integrity: sha512-sfyM/9gxFabdMTFt4quvLJuKbXS6StGIUf7Cp3l8aV2WqCURJevdpN6wW8XtGBo/iSnAP52ERwMRdyIavPYruw==} + '@napi-rs/tar-darwin-arm64@1.1.0': + resolution: {integrity: sha512-Zz2sXRzjIX4e532zD6xm2SjXEym6MkvfCvL2RMpG2+UwNVDVscHNcz3d47Pf3sysP2e2af7fBB3TIoK2f6trPw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/tar-darwin-x64@0.1.5': - resolution: {integrity: sha512-NtY8bADKE/3ODBM3hW/RgPeeERJpI6/jgipT3eLJ/CQWY1VJ6t9GHR7anJKhx1oxVdmSfqfCGMolM8WPV9x9bw==} + '@napi-rs/tar-darwin-x64@1.1.0': + resolution: {integrity: sha512-EI+CptIMNweT0ms9S3mkP/q+J6FNZ1Q6pvpJOEcWglRfyfQpLqjlC0O+dptruTPE8VamKYuqdjxfqD8hifZDOA==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/tar-freebsd-x64@0.1.5': - resolution: {integrity: sha512-azl0nWrDJAGg25cGVKEY7UtU5ABGz4sQASKvemDLwGbzMDtkJgCoPb+OunI1pezijRAyhiuZEQ4jK8S1qNAWCg==} + '@napi-rs/tar-freebsd-x64@1.1.0': + resolution: {integrity: sha512-J0PIqX+pl6lBIAckL/c87gpodLbjZB1OtIK+RDscKC9NLdpVv6VGOxzUV/fYev/hctcE8EfkLbgFOfpmVQPg2g==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/tar-linux-arm-gnueabihf@0.1.5': - resolution: {integrity: sha512-OjGdKjaW7b0m96rAvsLthMBhwYSSgpTM/WkHqRJo91HCYQ6tHXDBnq4VIQx2FpwT1PoetvRsbSgy0tOc95iYjA==} + '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': + resolution: {integrity: sha512-SLgIQo3f3EjkZ82ZwvrEgFvMdDAhsxCYjyoSuWfHCz0U16qx3SuGCp8+FYOPYCECHN3ZlGjXnoAIt9ERd0dEUg==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - '@napi-rs/tar-linux-arm64-gnu@0.1.5': - resolution: {integrity: sha512-o3b2VE5c7+NFb6XRcXrdXgur1yhpx+XNItFoeJUMBE8z0AGAISf2DJSbcJawmefUvrGtr+iLr61hsr6f2hw+5Q==} + '@napi-rs/tar-linux-arm64-gnu@1.1.0': + resolution: {integrity: sha512-d014cdle52EGaH6GpYTQOP9Py7glMO1zz/+ynJPjjzYFSxvdYx0byrjumZk2UQdIyGZiJO2MEFpCkEEKFSgPYA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/tar-linux-arm64-musl@0.1.5': - resolution: {integrity: sha512-5xTxsoPVqovnZ197CqTc+q3psRM4i+ErdiyfDgkG4nP045jh50gp22WKZuE24dc7/iS+IyUrM3+PRbmj2mzR8g==} + '@napi-rs/tar-linux-arm64-musl@1.1.0': + resolution: {integrity: sha512-L/y1/26q9L/uBqiW/JdOb/Dc94egFvNALUZV2WCGKQXc6UByPBMgdiEyW2dtoYxYYYYc+AKD+jr+wQPcvX2vrQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/tar-linux-ppc64-gnu@0.1.5': - resolution: {integrity: sha512-7FF1u8EkDpCEPCgU0/kvuzsO+opB7eIbsGfKRIbOqrDT7c1DYxDetNTtukPvNoT2kvwfxxThgTfcPADPxdOE/w==} + '@napi-rs/tar-linux-ppc64-gnu@1.1.0': + resolution: {integrity: sha512-EPE1K/80RQvPbLRJDJs1QmCIcH+7WRi0F73+oTe1582y9RtfGRuzAkzeBuAGRXAQEjRQw/RjtNqr6UTJ+8UuWQ==} engines: {node: '>= 10'} cpu: [ppc64] os: [linux] - '@napi-rs/tar-linux-s390x-gnu@0.1.5': - resolution: {integrity: sha512-uyIZ7OLCLHtVBpogoJUD0GSAF1IUa3d5c5AVUemTLIwYkVgzdEB+khh3i2+/oKObf79ZKfQ8mYxOryHqfx+ulw==} + '@napi-rs/tar-linux-s390x-gnu@1.1.0': + resolution: {integrity: sha512-B2jhWiB1ffw1nQBqLUP1h4+J1ovAxBOoe5N2IqDMOc63fsPZKNqF1PvO/dIem8z7LL4U4bsfmhy3gBfu547oNQ==} engines: {node: '>= 10'} cpu: [s390x] os: [linux] - '@napi-rs/tar-linux-x64-gnu@0.1.5': - resolution: {integrity: sha512-y8pFyVTU6lSYiW2lse6i1Ns9yt9mBkAqPbcJnIjqC7ZqRd61T6g3XZDSrKmsM6ycTfsAqoE5WyyFxBjQN29AOA==} + '@napi-rs/tar-linux-x64-gnu@1.1.0': + resolution: {integrity: sha512-tbZDHnb9617lTnsDMGo/eAMZxnsQFnaRe+MszRqHguKfMwkisc9CCJnks/r1o84u5fECI+J/HOrKXgczq/3Oww==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/tar-linux-x64-musl@0.1.5': - resolution: {integrity: sha512-8phLYc0QX+tqvp34PQHUulZUi4sy/fdg1KgFHiyYExTRRleBB01vM7KSn7Bk9dwH7lannO5D7j4O8OY46Xcr/A==} + '@napi-rs/tar-linux-x64-musl@1.1.0': + resolution: {integrity: sha512-dV6cODlzbO8u6Anmv2N/ilQHq/AWz0xyltuXoLU3yUyXbZcnWYZuB2rL8OBGPmqNcD+x9NdScBNXh7vWN0naSQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/tar-wasm32-wasi@0.1.5': - resolution: {integrity: sha512-OpVWC/bwY0zb6nbQDg6koxeZGb441gXwPkaYVjaK4O0TJjNpRKbokLAMlGFtcc/sVSPjghFL0+enfnLDt/P7og==} + '@napi-rs/tar-wasm32-wasi@1.1.0': + resolution: {integrity: sha512-jIa9nb2HzOrfH0F8QQ9g3WE4aMH5vSI5/1NYVNm9ysCmNjCCtMXCAhlI3WKCdm/DwHf0zLqdrrtDFXODcNaqMw==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/tar-win32-arm64-msvc@0.1.5': - resolution: {integrity: sha512-FXwQA2Ib55q98szshvDsitgo2iLW2lTD1Q53e8dPMGobPa2yL5e8IjJDCcMI7XJwBZPl9YjJk7nAb8y20DXF+Q==} + '@napi-rs/tar-win32-arm64-msvc@1.1.0': + resolution: {integrity: sha512-vfpG71OB0ijtjemp3WTdmBKJm9R70KM8vsSExMsIQtV0lVzP07oM1CW6JbNRPXNLhRoue9ofYLiUDk8bE0Hckg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/tar-win32-ia32-msvc@0.1.5': - resolution: {integrity: sha512-XEt58yFslNkwf2yJ+uX5nDNmPAk15Metkx2hVPeH29mOpuG2H8nuS8/42hZ+dQfZf3xABRjyurVMMH9JcgLZIQ==} + '@napi-rs/tar-win32-ia32-msvc@1.1.0': + resolution: {integrity: sha512-hGPyPW60YSpOSgzfy68DLBHgi6HxkAM+L59ZZZPMQ0TOXjQg+p2EW87+TjZfJOkSpbYiEkULwa/f4a2hcVjsqQ==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/tar-win32-x64-msvc@0.1.5': - resolution: {integrity: sha512-9Rq0Ob4S5NGFwNL3kGQkgrYlObqQgw19QMSZdVuhzZ9sSxn9OSF5cWgZ/n1oMEPWK+u6n9GSN2XbPn4DI7pm7Q==} + '@napi-rs/tar-win32-x64-msvc@1.1.0': + resolution: {integrity: sha512-L6Ed1DxXK9YSCMyvpR8MiNAyKNkQLjsHsHK9E0qnHa8NzLFqzDKhvs5LfnWxM2kJ+F7m/e5n9zPm24kHb3LsVw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/tar@0.1.5': - resolution: {integrity: sha512-skgWKcpjtUqJUk1jwhVl8vXYCXQlFC532KiryU3hQBr6ZIJk0E0qD9FG99hUqtPko8mIMS5HDPO+uSnvHfgRVg==} + '@napi-rs/tar@1.1.0': + resolution: {integrity: sha512-7cmzIu+Vbupriudo7UudoMRH2OA3cTw67vva8MxeoAe5S7vPFI7z0vp0pMXiA25S8IUJefImQ90FeJjl8fjEaQ==} engines: {node: '>= 10'} - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} + '@napi-rs/wasm-runtime@1.0.7': + resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} - '@napi-rs/wasm-tools-android-arm-eabi@0.0.3': - resolution: {integrity: sha512-T2tme8w5jZ/ZCjJurqNtKCxYtGoDjW9v2rn1bfI60ewCfkYXNpxrTURdkOib85sz+BcwmOfXn0enbg5W9KohoQ==} + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': + resolution: {integrity: sha512-lr07E/l571Gft5v4aA1dI8koJEmF1F0UigBbsqg9OWNzg80H3lDPO+auv85y3T/NHE3GirDk7x/D3sLO57vayw==} engines: {node: '>= 10'} cpu: [arm] os: [android] - '@napi-rs/wasm-tools-android-arm64@0.0.3': - resolution: {integrity: sha512-siHTjrxxBrvsVty5X2jI5waAyzJpr756GqGVUqxqS2eoTuqYRfgaFNvX8asp9LAagFtOojfD0fZfuvxK7dc4Rw==} + '@napi-rs/wasm-tools-android-arm64@1.0.1': + resolution: {integrity: sha512-WDR7S+aRLV6LtBJAg5fmjKkTZIdrEnnQxgdsb7Cf8pYiMWBHLU+LC49OUVppQ2YSPY0+GeYm9yuZWW3kLjJ7Bg==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - '@napi-rs/wasm-tools-darwin-arm64@0.0.3': - resolution: {integrity: sha512-0MqsSOYJ4jXcLv/nAInS8nwU+/hL0rSEJo7JXKj3dhkT9UNSj4zfidcOaIb05O9VskJBPmV040+edtWPHXNt2Q==} + '@napi-rs/wasm-tools-darwin-arm64@1.0.1': + resolution: {integrity: sha512-qWTI+EEkiN0oIn/N2gQo7+TVYil+AJ20jjuzD2vATS6uIjVz+Updeqmszi7zq7rdFTLp6Ea3/z4kDKIfZwmR9g==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@napi-rs/wasm-tools-darwin-x64@0.0.3': - resolution: {integrity: sha512-yXAK2mrlBMZZYK/59JRHZu/c683HFpr5ork1cn++fy8gqUBRLbjuq47VDjA7oyLW5SmWqNDhmhjFTDGvfIvcUg==} + '@napi-rs/wasm-tools-darwin-x64@1.0.1': + resolution: {integrity: sha512-bA6hubqtHROR5UI3tToAF/c6TDmaAgF0SWgo4rADHtQ4wdn0JeogvOk50gs2TYVhKPE2ZD2+qqt7oBKB+sxW3A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@napi-rs/wasm-tools-freebsd-x64@0.0.3': - resolution: {integrity: sha512-K1rne814utBd9Zo9LCggQ5h0TSnzGPzA+sG78Qr7KfFz8XQxEGDRH5wpzXyF1KaKav2RmO6wGMXlasDgIcq7GA==} + '@napi-rs/wasm-tools-freebsd-x64@1.0.1': + resolution: {integrity: sha512-90+KLBkD9hZEjPQW1MDfwSt5J1L46EUKacpCZWyRuL6iIEO5CgWU0V/JnEgFsDOGyyYtiTvHc5bUdUTWd4I9Vg==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - '@napi-rs/wasm-tools-linux-arm64-gnu@0.0.3': - resolution: {integrity: sha512-Yu3gtpvGc2+hcay3SU5MK7EMrGPBq/V4i8mpw/MEYUCzOb7Vd9aL8CryElzlk0SIbktG08VYMdhFFFoJAjlYtg==} + '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': + resolution: {integrity: sha512-rG0QlS65x9K/u3HrKafDf8cFKj5wV2JHGfl8abWgKew0GVPyp6vfsDweOwHbWAjcHtp2LHi6JHoW80/MTHm52Q==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/wasm-tools-linux-arm64-musl@0.0.3': - resolution: {integrity: sha512-XN+sPgEwFw3P47wDvtcQyOoZNghIL8gaiRjEGzprB+kE9N21GkuMbk3kdjiBBJkjqKF25f4fbOvNAY0jQEAO3A==} + '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': + resolution: {integrity: sha512-jAasbIvjZXCgX0TCuEFQr+4D6Lla/3AAVx2LmDuMjgG4xoIXzjKWl7c4chuaD+TI+prWT0X6LJcdzFT+ROKGHQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - '@napi-rs/wasm-tools-linux-x64-gnu@0.0.3': - resolution: {integrity: sha512-mfMvMEqn33YtEjIyLPguZ6yDsNtF5zV7mqc99620YDyj2SLa0aI35TNTc7Dm+/hlgqHRKhdudsWGfYc4dBND2Q==} + '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': + resolution: {integrity: sha512-Plgk5rPqqK2nocBGajkMVbGm010Z7dnUgq0wtnYRZbzWWxwWcXfZMPa8EYxrK4eE8SzpI7VlZP1tdVsdjgGwMw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/wasm-tools-linux-x64-musl@0.0.3': - resolution: {integrity: sha512-KXMsXWGELoN5xgPCoRHbgt5TScSx8BK2GcCHKJ9OPZ2HMfsXbLgS/SNi6vz1CbLMZMLPBY2G6HAk0gzLGyS0mQ==} + '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': + resolution: {integrity: sha512-GW7AzGuWxtQkyHknHWYFdR0CHmW6is8rG2Rf4V6GNmMpmwtXt/ItWYWtBe4zqJWycMNazpfZKSw/BpT7/MVCXQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - '@napi-rs/wasm-tools-wasm32-wasi@0.0.3': - resolution: {integrity: sha512-v3iMHnAfMteogpbqHTFeLXPeAzL5AhpDJLvZvLXbuRiMsMRL0dn8CbcEnYja2P/Ui6Xlyky6PcaUsepOUTNb7A==} + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': + resolution: {integrity: sha512-/nQVSTrqSsn7YdAc2R7Ips/tnw5SPUcl3D7QrXCNGPqjbatIspnaexvaOYNyKMU6xPu+pc0BTnKVmqhlJJCPLA==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@napi-rs/wasm-tools-win32-arm64-msvc@0.0.3': - resolution: {integrity: sha512-HWrg9cW+u+rQKL9XCQILaGGs6mDYdwX9nwcTIvJAjrpGWu8Dp4wz6i66w6YKHqVng1suGYjjr+LH4/1e0tDaAg==} + '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': + resolution: {integrity: sha512-PFi7oJIBu5w7Qzh3dwFea3sHRO3pojMsaEnUIy22QvsW+UJfNQwJCryVrpoUt8m4QyZXI+saEq/0r4GwdoHYFQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@napi-rs/wasm-tools-win32-ia32-msvc@0.0.3': - resolution: {integrity: sha512-h99hAWvQKhcloyPfPi0IjrvKRToTE9Z4UVXoXZhcjpCGmr3o1qW+1FAupRy/TcVdMjUJNLE/aenml3UPqzQEQw==} + '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': + resolution: {integrity: sha512-gXkuYzxQsgkj05Zaq+KQTkHIN83dFAwMcTKa2aQcpYPRImFm2AQzEyLtpXmyCWzJ0F9ZYAOmbSyrNew8/us6bw==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] - '@napi-rs/wasm-tools-win32-x64-msvc@0.0.3': - resolution: {integrity: sha512-7/6IpzMi9VGYxLcc9SJyu9ZIdbDwyyb09glVF/2SFEgke9F5H46XzRrAdSoRnjfcq/tdLyHKJbnpCIB257qVYg==} + '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': + resolution: {integrity: sha512-rEAf05nol3e3eei2sRButmgXP+6ATgm0/38MKhz9Isne82T4rPIMYsCIFj0kOisaGeVwoi2fnm7O9oWp5YVnYQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@napi-rs/wasm-tools@0.0.3': - resolution: {integrity: sha512-p7NT5wnOIwmP0f3KbXlMabeld5dPFsADpHMWJaBodTSmnPE8P4msguxKJLKWquqAS1FY2dsjBZ62K0/hfiqAUg==} + '@napi-rs/wasm-tools@1.0.1': + resolution: {integrity: sha512-enkZYyuCdo+9jneCPE/0fjIta4wWnvVN9hBo2HuiMpRF0q3lzv1J6b/cl7i0mxZUKhBrV3aCKDBQnCOhwKbPmQ==} engines: {node: '>= 10'} '@nodelib/fs.scandir@2.1.5': @@ -1068,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'} @@ -1081,8 +1296,8 @@ packages: rollup: optional: true - '@rollup/plugin-typescript@12.1.4': - resolution: {integrity: sha512-s5Hx+EtN60LMlDBvl5f04bEiFZmAepk27Q+mr85L/00zPDn1jtzlTV6FWn81MaIwqfWzKxmOJrBWHU6vtQyedQ==} + '@rollup/plugin-typescript@12.3.0': + resolution: {integrity: sha512-7DP0/p7y3t67+NabT9f8oTBFE6gGkto4SA6Np2oudYmZE/m1dt8RB0SjL1msMxFpLo631qjRCcBlAbq1ml/Big==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.14.0||^3.0.0||^4.0.0 @@ -1103,116 +1318,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.52.4': - resolution: {integrity: sha512-BTm2qKNnWIQ5auf4deoetINJm2JzvihvGb9R6K/ETwKLql/Bb3Eg2H1FBp1gUb4YGbydMA3jcmQTR73q7J+GAA==} + '@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.52.4': - resolution: {integrity: sha512-P9LDQiC5vpgGFgz7GSM6dKPCiqR3XYN1WwJKA4/BUVDjHpYsf3iBEmVz62uyq20NGYbiGPR5cNHI7T1HqxNs2w==} + '@rollup/rollup-android-arm64@4.55.2': + resolution: {integrity: sha512-eXBg7ibkNUZ+sTwbFiDKou0BAckeV6kIigK7y5Ko4mB/5A1KLhuzEKovsmfvsL8mQorkoincMFGnQuIT92SKqA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.52.4': - resolution: {integrity: sha512-QRWSW+bVccAvZF6cbNZBJwAehmvG9NwfWHwMy4GbWi/BQIA/laTIktebT2ipVjNncqE6GLPxOok5hsECgAxGZg==} + '@rollup/rollup-darwin-arm64@4.55.2': + resolution: {integrity: sha512-UCbaTklREjrc5U47ypLulAgg4njaqfOVLU18VrCrI+6E5MQjuG0lSWaqLlAJwsD7NpFV249XgB0Bi37Zh5Sz4g==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.52.4': - resolution: {integrity: sha512-hZgP05pResAkRJxL1b+7yxCnXPGsXU0fG9Yfd6dUaoGk+FhdPKCJ5L1Sumyxn8kvw8Qi5PvQ8ulenUbRjzeCTw==} + '@rollup/rollup-darwin-x64@4.55.2': + resolution: {integrity: sha512-dP67MA0cCMHFT2g5XyjtpVOtp7y4UyUxN3dhLdt11at5cPKnSm4lY+EhwNvDXIMzAMIo2KU+mc9wxaAQJTn7sQ==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.52.4': - resolution: {integrity: sha512-xmc30VshuBNUd58Xk4TKAEcRZHaXlV+tCxIXELiE9sQuK3kG8ZFgSPi57UBJt8/ogfhAF5Oz4ZSUBN77weM+mQ==} + '@rollup/rollup-freebsd-arm64@4.55.2': + resolution: {integrity: sha512-WDUPLUwfYV9G1yxNRJdXcvISW15mpvod1Wv3ok+Ws93w1HjIVmCIFxsG2DquO+3usMNCpJQ0wqO+3GhFdl6Fow==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.52.4': - resolution: {integrity: sha512-WdSLpZFjOEqNZGmHflxyifolwAiZmDQzuOzIq9L27ButpCVpD7KzTRtEG1I0wMPFyiyUdOO+4t8GvrnBLQSwpw==} + '@rollup/rollup-freebsd-x64@4.55.2': + resolution: {integrity: sha512-Ng95wtHVEulRwn7R0tMrlUuiLVL/HXA8Lt/MYVpy88+s5ikpntzZba1qEulTuPnPIZuOPcW9wNEiqvZxZmgmqQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': - resolution: {integrity: sha512-xRiOu9Of1FZ4SxVbB0iEDXc4ddIcjCv2aj03dmW8UrZIW7aIQ9jVJdLBIhxBI+MaTnGAKyvMwPwQnoOEvP7FgQ==} + '@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.52.4': - resolution: {integrity: sha512-FbhM2p9TJAmEIEhIgzR4soUcsW49e9veAQCziwbR+XWB2zqJ12b4i/+hel9yLiD8pLncDH4fKIPIbt5238341Q==} + '@rollup/rollup-linux-arm-musleabihf@4.55.2': + resolution: {integrity: sha512-ZV7EljjBDwBBBSv570VWj0hiNTdHt9uGznDtznBB4Caj3ch5rgD4I2K1GQrtbvJ/QiB+663lLgOdcADMNVC29Q==} cpu: [arm] os: [linux] - '@rollup/rollup-linux-arm64-gnu@4.52.4': - resolution: {integrity: sha512-4n4gVwhPHR9q/g8lKCyz0yuaD0MvDf7dV4f9tHt0C73Mp8h38UCtSCSE6R9iBlTbXlmA8CjpsZoujhszefqueg==} + '@rollup/rollup-linux-arm64-gnu@4.55.2': + resolution: {integrity: sha512-uvjwc8NtQVPAJtq4Tt7Q49FOodjfbf6NpqXyW/rjXoV+iZ3EJAHLNAnKT5UJBc6ffQVgmXTUL2ifYiLABlGFqA==} cpu: [arm64] os: [linux] - '@rollup/rollup-linux-arm64-musl@4.52.4': - resolution: {integrity: sha512-u0n17nGA0nvi/11gcZKsjkLj1QIpAuPFQbR48Subo7SmZJnGxDpspyw2kbpuoQnyK+9pwf3pAoEXerJs/8Mi9g==} + '@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.52.4': - resolution: {integrity: sha512-0G2c2lpYtbTuXo8KEJkDkClE/+/2AFPdPAbmaHoE870foRFs4pBrDehilMcrSScrN/fB/1HTaWO4bqw+ewBzMQ==} + '@rollup/rollup-linux-loong64-gnu@4.55.2': + resolution: {integrity: sha512-gi21faacK+J8aVSyAUptML9VQN26JRxe484IbF+h3hpG+sNVoMXPduhREz2CcYr5my0NE3MjVvQ5bMKX71pfVA==} cpu: [loong64] os: [linux] - '@rollup/rollup-linux-ppc64-gnu@4.52.4': - resolution: {integrity: sha512-teSACug1GyZHmPDv14VNbvZFX779UqWTsd7KtTM9JIZRDI5NUwYSIS30kzI8m06gOPB//jtpqlhmraQ68b5X2g==} + '@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.2': + resolution: {integrity: sha512-rPyuLFNoF1B0+wolH277E780NUKf+KoEDb3OyoLbAO18BbeKi++YN6gC/zuJoPPDlQRL3fIxHxCxVEWiem2yXw==} cpu: [ppc64] os: [linux] - '@rollup/rollup-linux-riscv64-gnu@4.52.4': - resolution: {integrity: sha512-/MOEW3aHjjs1p4Pw1Xk4+3egRevx8Ji9N6HUIA1Ifh8Q+cg9dremvFCUbOX2Zebz80BwJIgCBUemjqhU5XI5Eg==} + '@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.2': + resolution: {integrity: sha512-i+sGeRGsjKZcQRh3BRfpLsM3LX3bi4AoEVqmGDyc50L6KfYsN45wVCSz70iQMwPWr3E5opSiLOwsC9WB4/1pqg==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-riscv64-musl@4.52.4': - resolution: {integrity: sha512-1HHmsRyh845QDpEWzOFtMCph5Ts+9+yllCrREuBR/vg2RogAQGGBRC8lDPrPOMnrdOJ+mt1WLMOC2Kao/UwcvA==} + '@rollup/rollup-linux-riscv64-musl@4.55.2': + resolution: {integrity: sha512-C1vLcKc4MfFV6I0aWsC7B2Y9QcsiEcvKkfxprwkPfLaN8hQf0/fKHwSF2lcYzA9g4imqnhic729VB9Fo70HO3Q==} cpu: [riscv64] os: [linux] - '@rollup/rollup-linux-s390x-gnu@4.52.4': - resolution: {integrity: sha512-seoeZp4L/6D1MUyjWkOMRU6/iLmCU2EjbMTyAG4oIOs1/I82Y5lTeaxW0KBfkUdHAWN7j25bpkt0rjnOgAcQcA==} + '@rollup/rollup-linux-s390x-gnu@4.55.2': + resolution: {integrity: sha512-68gHUK/howpQjh7g7hlD9DvTTt4sNLp1Bb+Yzw2Ki0xvscm2cOdCLZNJNhd2jW8lsTPrHAHuF751BygifW4bkQ==} cpu: [s390x] os: [linux] - '@rollup/rollup-linux-x64-gnu@4.52.4': - resolution: {integrity: sha512-Wi6AXf0k0L7E2gteNsNHUs7UMwCIhsCTs6+tqQ5GPwVRWMaflqGec4Sd8n6+FNFDw9vGcReqk2KzBDhCa1DLYg==} + '@rollup/rollup-linux-x64-gnu@4.55.2': + resolution: {integrity: sha512-1e30XAuaBP1MAizaOBApsgeGZge2/Byd6wV4a8oa6jPdHELbRHBiw7wvo4dp7Ie2PE8TZT4pj9RLGZv9N4qwlw==} cpu: [x64] os: [linux] - '@rollup/rollup-linux-x64-musl@4.52.4': - resolution: {integrity: sha512-dtBZYjDmCQ9hW+WgEkaffvRRCKm767wWhxsFW3Lw86VXz/uJRuD438/XvbZT//B96Vs8oTA8Q4A0AfHbrxP9zw==} + '@rollup/rollup-linux-x64-musl@4.55.2': + resolution: {integrity: sha512-4BJucJBGbuGnH6q7kpPqGJGzZnYrpAzRd60HQSt3OpX/6/YVgSsJnNzR8Ot74io50SeVT4CtCWe/RYIAymFPwA==} cpu: [x64] os: [linux] - '@rollup/rollup-openharmony-arm64@4.52.4': - resolution: {integrity: sha512-1ox+GqgRWqaB1RnyZXL8PD6E5f7YyRUJYnCqKpNzxzP0TkaUh112NDrR9Tt+C8rJ4x5G9Mk8PQR3o7Ku2RKqKA==} + '@rollup/rollup-openbsd-x64@4.55.2': + resolution: {integrity: sha512-cT2MmXySMo58ENv8p6/O6wI/h/gLnD3D6JoajwXFZH6X9jz4hARqUhWpGuQhOgLNXscfZYRQMJvZDtWNzMAIDw==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.55.2': + resolution: {integrity: sha512-sZnyUgGkuzIXaK3jNMPmUIyJrxu/PjmATQrocpGA1WbCPX8H5tfGgRSuYtqBYAvLuIGp8SPRb1O4d1Fkb5fXaQ==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.52.4': - resolution: {integrity: sha512-8GKr640PdFNXwzIE0IrkMWUNUomILLkfeHjXBi/nUvFlpZP+FA8BKGKpacjW6OUUHaNI6sUURxR2U2g78FOHWQ==} + '@rollup/rollup-win32-arm64-msvc@4.55.2': + resolution: {integrity: sha512-sDpFbenhmWjNcEbBcoTV0PWvW5rPJFvu+P7XoTY0YLGRupgLbFY0XPfwIbJOObzO7QgkRDANh65RjhPmgSaAjQ==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.52.4': - resolution: {integrity: sha512-AIy/jdJ7WtJ/F6EcfOb2GjR9UweO0n43jNObQMb6oGxkYTfLcnN7vYYpG+CN3lLxrQkzWnMOoNSHTW54pgbVxw==} + '@rollup/rollup-win32-ia32-msvc@4.55.2': + resolution: {integrity: sha512-GvJ03TqqaweWCigtKQVBErw2bEhu1tyfNQbarwr94wCGnczA9HF8wqEe3U/Lfu6EdeNP0p6R+APeHVwEqVxpUQ==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.52.4': - resolution: {integrity: sha512-UF9KfsH9yEam0UjTwAgdK0anlQ7c8/pWPU2yVjyWcF1I1thABt6WXE47cI71pGiZ8wGvxohBoLnxM04L/wj8mQ==} + '@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.52.4': - resolution: {integrity: sha512-bf9PtUa0u8IXDVxzRToFQKsNCRz9qLYfR/MpECxl4mRoWYjAeFjgxj1XdZr2M/GNVpT05p+LgQOHopYDlUu6/w==} + '@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==} + '@sveltejs/acorn-typescript@1.0.5': resolution: {integrity: sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==} peerDependencies: @@ -1233,8 +1473,8 @@ packages: svelte: ^5.0.0 vite: ^6.3.0 || ^7.0.0 - '@tybys/wasm-util@0.10.0': - resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@tybys/wasm-util@0.10.1': + resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} '@types/chai@5.2.2': resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} @@ -1251,8 +1491,8 @@ packages: '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/node@22.15.32': - resolution: {integrity: sha512-3jigKqgSjsH6gYZv2nEsqdXfZqIFGAV36XYYjf9KGZ3PSG+IhLecqPnI310RvjutyMwifE2hhhNEklOUrvx/wA==} + '@types/node@24.10.0': + resolution: {integrity: sha512-qzQZRBqkFsYyaSWXuEHc2WR9c0a0CXwiE5FWUvn7ZM+vdy1uZLfCunD38UzhuB7YN/J11ndbDBcTmOdxJo9Q7A==} '@typescript-eslint/eslint-plugin@8.34.1': resolution: {integrity: sha512-STXcN6ebF6li4PxwNeFnqF8/2BNDvBupf2OPx2yWNzr6mKNGF7q49VM00Pz5FaomJyqvbXpY6PhO+T9w139YEQ==} @@ -1402,34 +1642,34 @@ packages: peerDependencies: vite: ^2.9.0 || ^3.0.0-0 || ^4.0.0 || ^5.0.0-0 || ^6.0.0-0 || ^7.0.0-0 - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@vitest/expect@4.0.6': + resolution: {integrity: sha512-5j8UUlBVhOjhj4lR2Nt9sEV8b4WtbcYh8vnfhTNA2Kn5+smtevzjNq+xlBuVhnFGXiyPPNzGrOVvmyHWkS5QGg==} - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + '@vitest/mocker@4.0.6': + resolution: {integrity: sha512-3COEIew5HqdzBFEYN9+u0dT3i/NCwppLnO1HkjGfAP1Vs3vti1Hxm/MvcbC4DAn3Szo1M7M3otiAaT83jvqIjA==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0-0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@vitest/pretty-format@4.0.6': + resolution: {integrity: sha512-4vptgNkLIA1W1Nn5X4x8rLJBzPiJwnPc+awKtfBE5hNMVsoAl/JCCPPzNrbf+L4NKgklsis5Yp2gYa+XAS442g==} - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@vitest/runner@4.0.6': + resolution: {integrity: sha512-trPk5qpd7Jj+AiLZbV/e+KiiaGXZ8ECsRxtnPnCrJr9OW2mLB72Cb824IXgxVz/mVU3Aj4VebY+tDTPn++j1Og==} - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@vitest/snapshot@4.0.6': + resolution: {integrity: sha512-PaYLt7n2YzuvxhulDDu6c9EosiRuIE+FI2ECKs6yvHyhoga+2TBWI8dwBjs+IeuQaMtZTfioa9tj3uZb7nev1g==} - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@vitest/spy@4.0.6': + resolution: {integrity: sha512-g9jTUYPV1LtRPRCQfhbMintW7BTQz1n6WXYQYRQ25qkyffA4bjVXjkROokZnv7t07OqfaFKw1lPzqKGk1hmNuQ==} - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@vitest/utils@4.0.6': + resolution: {integrity: sha512-bG43VS3iYKrMIZXBo+y8Pti0O7uNju3KvNn6DrQWhQQKcLavMB+0NZfO1/QBAEbq0MaQ3QjNsnnXlGQvsh0Z6A==} '@vue/compiler-core@3.5.17': resolution: {integrity: sha512-Xe+AittLbAyV0pabcN7cP7/BenRBNcteM4aSDCtRvGw0d9OL+HG1u/XHLY/kt1q4fyMeZYXyIYrsHuPSiDPosA==} @@ -1482,10 +1722,6 @@ packages: ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - ansi-escapes@4.3.2: - resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} - engines: {node: '>=8'} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1505,13 +1741,6 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} - as-table@1.0.55: - resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - axobject-query@4.1.0: resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} @@ -1549,20 +1778,16 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - chai@5.2.0: - resolution: {integrity: sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==} - engines: {node: '>=12'} + chai@6.2.0: + resolution: {integrity: sha512-aUTnJc/JipRzJrNADXVvpVqi6CO0dn3nx4EVPxijri+fj3LUUDyZQOgVeW54Ob3Y1Xh9Iz8f+CgaCl8v0mn9bA==} + engines: {node: '>=18'} chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - chardet@0.7.0: - resolution: {integrity: sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==} - - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} + chardet@2.1.1: + resolution: {integrity: sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==} chokidar@3.6.0: resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} @@ -1588,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==} @@ -1611,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==} @@ -1628,14 +1846,11 @@ packages: resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + 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.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -1643,10 +1858,6 @@ packages: supports-color: optional: true - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -1660,13 +1871,21 @@ 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: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} + emnapi@1.7.1: + resolution: {integrity: sha512-wlLK2xFq+T+rCBlY6+lPlFVDEyE93b7hSn9dMrfWBIcPf4ArwUvymvvMnN9M5WWuiryYQe9M+UJrkqw4trdyRA==} + peerDependencies: + node-addon-api: '>= 6.1.0' + peerDependenciesMeta: + node-addon-api: + optional: true + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1674,14 +1893,25 @@ 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==} + es-toolkit@1.42.0: + resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} + esbuild@0.25.4: resolution: {integrity: sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==} 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'} @@ -1754,17 +1984,13 @@ packages: resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} engines: {node: '>=6'} - expect-type@1.2.1: - resolution: {integrity: sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} exsolve@1.0.7: resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} - external-editor@3.1.0: - resolution: {integrity: sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==} - engines: {node: '>=4'} - fast-content-type-parse@3.0.0: resolution: {integrity: sha512-ZvLdcY8P+N8mGQJahJV5G4U88CSvT1rP8ApL6uETe88MBXrBHAkZlSEySdUlyztF7ccb+Znos3TFqaepHxdhBg==} @@ -1805,10 +2031,6 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - find-up@7.0.0: - resolution: {integrity: sha512-YyZM99iHrqLKjmt4LJDj58KI+fYyufRLBSYcqycxf//KpBk9FoewoGX0450m9nB44qrZnovzC2oeP5hUibxc/g==} - engines: {node: '>=18'} - flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} @@ -1824,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'} @@ -1846,8 +2065,8 @@ packages: resolution: {integrity: sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==} engines: {node: '>=18'} - globals@16.2.0: - resolution: {integrity: sha512-O+7l9tPdHCU320IigZZPj5zmRCFG9xHmx9cU8FqU2Rp+JN714seHV+2S9+JslCpY4gJwU2vOGox0wzgae/MCEg==} + globals@17.0.0: + resolution: {integrity: sha512-gv5BeD2EssA793rlFWVPMMCqefTlpusw6/2TbAVMy0FzcG8wKJn4O+NqJ4+XWmmwrayJgw5TzrmWjFgmz1XPqw==} engines: {node: '>=18'} graphemer@1.4.0: @@ -1865,8 +2084,8 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + iconv-lite@0.7.0: + resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} engines: {node: '>=0.10.0'} ignore@5.3.2: @@ -1885,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'} @@ -1922,11 +2138,8 @@ packages: resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} hasBin: true - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + js-yaml@4.1.1: + resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true json-buffer@3.0.1: @@ -1963,21 +2176,11 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - locate-path@7.2.0: - resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - - lodash-es@4.17.21: - resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} - lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - loupe@3.1.4: - resolution: {integrity: sha512-wJzkKwJrheKtknCOKNEtDK4iqg/MxmZheEMtSTYvnzRdEYaZzmgH976nenp8WdJRdx5Vc1X/9MO0Oszl6ezeXg==} - - magic-string@0.30.19: - resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} mdn-data@2.12.2: resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} @@ -1995,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 @@ -2017,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} @@ -2043,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'} @@ -2054,18 +2250,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - p-limit@4.0.0: - resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} - p-locate@6.0.0: - resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - package-manager-detector@1.3.0: resolution: {integrity: sha512-ZsEbbZORsyHuO00lY1kV3/t72yp6Ysay6Pd17ZAlNGuGwmWDLCJxFpRs0IzfXfj1o4icJOkUEioexFHzyPurSQ==} @@ -2077,10 +2265,6 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-exists@5.0.0: - resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2094,10 +2278,6 @@ packages: pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - pathval@2.0.0: - resolution: {integrity: sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==} - engines: {node: '>= 14.16'} - perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} @@ -2126,14 +2306,11 @@ packages: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.5.3: - resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} 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'} @@ -2168,8 +2345,8 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rollup@4.52.4: - resolution: {integrity: sha512-CLEVl+MnPAiKh5pl4dEWSyMTpuflgNQiLGhMv8ezD5W/qP8AKvmYpCOKRRNOh7oRKnauBZ4SyeYkMS+1VSyKwQ==} + rollup@4.55.2: + resolution: {integrity: sha512-PggGy4dhwx5qaW+CKBilA/98Ql9keyfnb7lh4SR6shQ91QQQi1ORJ1v4UinkdP2i87OBs9AQFooQylcrrRfIcg==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -2185,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: @@ -2212,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'} @@ -2236,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==} @@ -2258,8 +2429,9 @@ packages: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + 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==} @@ -2291,22 +2463,10 @@ packages: resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} engines: {node: '>=12.0.0'} - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + tinyrainbow@3.0.3: + resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} engines: {node: '>=14.0.0'} - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} - engines: {node: '>=14.0.0'} - - tmp@0.2.5: - resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} - engines: {node: '>=14.14'} - to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} @@ -2331,10 +2491,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-fest@0.21.3: - resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} - engines: {node: '>=10'} - typescript-eslint@8.34.1: resolution: {integrity: sha512-XjS+b6Vg9oT1BaIUfkW3M3LvqZE++rbzAMEHuccCfO/YkP43ha6w3jTEMilQxMF92nVOYCcdjv1ZUhAa1D/0ow==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2353,19 +2509,15 @@ packages: unconfig@7.3.2: resolution: {integrity: sha512-nqG5NNL2wFVGZ0NA/aCFw0oJ2pxSf1lwg4Z5ill8wd7K4KX/rQbHlwbh+bjctXL5Ly1xtzHenHGOK0b+lG6JVg==} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + 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==} - - unicorn-magic@0.1.0: - resolution: {integrity: sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==} - engines: {node: '>=18'} + 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==} @@ -2389,13 +2541,8 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite@7.1.5: - resolution: {integrity: sha512-4cKBO9wR75r0BeIWWWId9XK9Lj6La5X846Zw9dFfzMRw38IlTk2iCcUt6hsyiDRcPidc55ZParFYDXi0nXOeLQ==} + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -2442,16 +2589,18 @@ packages: vite: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + vitest@4.0.6: + resolution: {integrity: sha512-gR7INfiVRwnEOkCk47faros/9McCZMp5LM+OMNWGLaDBSvJxIzwjgNFufkuePBNaesGRnLmNfW+ddbUJRZn0nQ==} + engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 + '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 4.0.6 + '@vitest/browser-preview': 4.0.6 + '@vitest/browser-webdriverio': 4.0.6 + '@vitest/ui': 4.0.6 happy-dom: '*' jsdom: '*' peerDependenciesMeta: @@ -2461,7 +2610,11 @@ packages: optional: true '@types/node': optional: true - '@vitest/browser': + '@vitest/browser-playwright': + optional: true + '@vitest/browser-preview': + optional: true + '@vitest/browser-webdriverio': optional: true '@vitest/ui': optional: true @@ -2483,9 +2636,6 @@ packages: typescript: optional: true - wasm-sjlj@1.0.6: - resolution: {integrity: sha512-pjaKtLJejlWm6+okPV2X1A6nIsRDD4qeK97eCh8DP8KXi3Nzn/HY01vpHhZHlhDri12eZqipjm8HhdTVw+ATxw==} - which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2500,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 @@ -2535,22 +2685,21 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yocto-queue@1.2.1: - resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} - engines: {node: '>=12.20'} - - yoctocolors-cjs@2.1.2: - resolution: {integrity: sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==} + yoctocolors-cjs@2.1.3: + 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: @@ -2568,58 +2717,58 @@ snapshots: '@babel/helper-string-parser@7.27.1': {} - '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/parser@7.28.4': + '@babel/parser@7.28.6': dependencies: - '@babel/types': 7.28.4 + '@babel/types': 7.28.6 - '@babel/types@7.28.4': + '@babel/types@7.28.6': dependencies: '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 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': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@emnapi/core@1.4.5': + '@emnapi/core@1.7.1': dependencies: - '@emnapi/wasi-threads': 1.0.4 + '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.4.3': + '@emnapi/runtime@1.8.1': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.0.4': + '@emnapi/wasi-threads@1.1.0': dependencies: tslib: 2.8.1 optional: true @@ -2629,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) @@ -2711,7 +2938,7 @@ snapshots: '@eslint/config-array@0.20.1': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.1 + debug: 4.4.3 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -2729,12 +2956,12 @@ snapshots: '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 - debug: 4.4.1 + debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 - js-yaml: 4.1.0 + js-yaml: 4.1.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -2749,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': @@ -2779,7 +3004,7 @@ snapshots: '@antfu/install-pkg': 1.1.0 '@antfu/utils': 8.1.1 '@iconify/types': 2.0.0 - debug: 4.4.1 + debug: 4.4.3 globals: 15.15.0 kolorist: 1.8.0 local-pkg: 1.1.1 @@ -2787,196 +3012,226 @@ 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.4.3 + '@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 - '@inquirer/checkbox@4.1.9(@types/node@22.15.32)': + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@inquirer/ansi@1.0.2': {} + + '@inquirer/checkbox@4.3.2(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7(@types/node@22.15.32) - ansi-escapes: 4.3.2 - yoctocolors-cjs: 2.1.2 + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.10.0) + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/confirm@5.1.13(@types/node@22.15.32)': + '@inquirer/confirm@5.1.21(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/core@10.1.14(@types/node@22.15.32)': + '@inquirer/core@10.3.2(@types/node@24.10.0)': dependencies: - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7(@types/node@22.15.32) - ansi-escapes: 4.3.2 + '@inquirer/ansi': 1.0.2 + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.10.0) cli-width: 4.1.0 mute-stream: 2.0.0 signal-exit: 4.1.0 wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.2 + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/editor@4.2.14(@types/node@22.15.32)': + '@inquirer/editor@4.2.23(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) - external-editor: 3.1.0 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/external-editor': 1.0.3(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/expand@4.0.16(@types/node@22.15.32)': + '@inquirer/expand@4.0.23(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/figures@1.0.12': {} - - '@inquirer/input@4.2.0(@types/node@22.15.32)': + '@inquirer/external-editor@1.0.3(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) + chardet: 2.1.1 + iconv-lite: 0.7.0 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/number@3.0.16(@types/node@22.15.32)': + '@inquirer/figures@1.0.15': {} + + '@inquirer/input@4.3.1(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/password@4.0.16(@types/node@22.15.32)': + '@inquirer/number@3.0.23(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) - ansi-escapes: 4.3.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/prompts@7.6.0(@types/node@22.15.32)': + '@inquirer/password@4.0.23(@types/node@24.10.0)': dependencies: - '@inquirer/checkbox': 4.1.9(@types/node@22.15.32) - '@inquirer/confirm': 5.1.13(@types/node@22.15.32) - '@inquirer/editor': 4.2.14(@types/node@22.15.32) - '@inquirer/expand': 4.0.16(@types/node@22.15.32) - '@inquirer/input': 4.2.0(@types/node@22.15.32) - '@inquirer/number': 3.0.16(@types/node@22.15.32) - '@inquirer/password': 4.0.16(@types/node@22.15.32) - '@inquirer/rawlist': 4.1.4(@types/node@22.15.32) - '@inquirer/search': 3.0.16(@types/node@22.15.32) - '@inquirer/select': 4.2.4(@types/node@22.15.32) + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/rawlist@4.1.4(@types/node@22.15.32)': + '@inquirer/prompts@7.10.1(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/type': 3.0.7(@types/node@22.15.32) - yoctocolors-cjs: 2.1.2 + '@inquirer/checkbox': 4.3.2(@types/node@24.10.0) + '@inquirer/confirm': 5.1.21(@types/node@24.10.0) + '@inquirer/editor': 4.2.23(@types/node@24.10.0) + '@inquirer/expand': 4.0.23(@types/node@24.10.0) + '@inquirer/input': 4.3.1(@types/node@24.10.0) + '@inquirer/number': 3.0.23(@types/node@24.10.0) + '@inquirer/password': 4.0.23(@types/node@24.10.0) + '@inquirer/rawlist': 4.1.11(@types/node@24.10.0) + '@inquirer/search': 3.2.2(@types/node@24.10.0) + '@inquirer/select': 4.4.2(@types/node@24.10.0) optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/search@3.0.16(@types/node@22.15.32)': + '@inquirer/rawlist@4.1.11(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7(@types/node@22.15.32) - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/type': 3.0.10(@types/node@24.10.0) + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/select@4.2.4(@types/node@22.15.32)': + '@inquirer/search@3.2.2(@types/node@24.10.0)': dependencies: - '@inquirer/core': 10.1.14(@types/node@22.15.32) - '@inquirer/figures': 1.0.12 - '@inquirer/type': 3.0.7(@types/node@22.15.32) - ansi-escapes: 4.3.2 - yoctocolors-cjs: 2.1.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.10.0) + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 - '@inquirer/type@3.0.7(@types/node@22.15.32)': + '@inquirer/select@4.4.2(@types/node@24.10.0)': + dependencies: + '@inquirer/ansi': 1.0.2 + '@inquirer/core': 10.3.2(@types/node@24.10.0) + '@inquirer/figures': 1.0.15 + '@inquirer/type': 3.0.10(@types/node@24.10.0) + yoctocolors-cjs: 2.1.3 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 + + '@inquirer/type@3.0.10(@types/node@24.10.0)': + optionalDependencies: + '@types/node': 24.10.0 '@jridgewell/gen-mapping@0.3.12': dependencies: @@ -3002,246 +3257,250 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@napi-rs/cli@3.0.0(@emnapi/runtime@1.4.3)(@types/node@22.15.32)': + '@napi-rs/cli@3.4.1(@emnapi/runtime@1.8.1)(@types/node@24.10.0)': dependencies: - '@inquirer/prompts': 7.6.0(@types/node@22.15.32) - '@napi-rs/cross-toolchain': 0.0.19 - '@napi-rs/wasm-tools': 0.0.3 + '@inquirer/prompts': 7.10.1(@types/node@24.10.0) + '@napi-rs/cross-toolchain': 1.0.3 + '@napi-rs/wasm-tools': 1.0.1 '@octokit/rest': 22.0.0 clipanion: 4.0.0-rc.4(typanion@3.14.0) colorette: 2.0.20 - debug: 4.4.1 - find-up: 7.0.0 - js-yaml: 4.1.0 - lodash-es: 4.17.21 - semver: 7.7.2 + debug: 4.4.3 + emnapi: 1.7.1 + es-toolkit: 1.42.0 + js-yaml: 4.1.1 + semver: 7.7.3 typanion: 3.14.0 - wasm-sjlj: 1.0.6 optionalDependencies: - '@emnapi/runtime': 1.4.3 + '@emnapi/runtime': 1.8.1 transitivePeerDependencies: - '@napi-rs/cross-toolchain-arm64-target-aarch64' - '@napi-rs/cross-toolchain-arm64-target-armv7' + - '@napi-rs/cross-toolchain-arm64-target-ppc64le' + - '@napi-rs/cross-toolchain-arm64-target-s390x' - '@napi-rs/cross-toolchain-arm64-target-x86_64' - '@napi-rs/cross-toolchain-x64-target-aarch64' - '@napi-rs/cross-toolchain-x64-target-armv7' + - '@napi-rs/cross-toolchain-x64-target-ppc64le' + - '@napi-rs/cross-toolchain-x64-target-s390x' - '@napi-rs/cross-toolchain-x64-target-x86_64' - '@types/node' + - node-addon-api - supports-color - '@napi-rs/cross-toolchain@0.0.19': + '@napi-rs/cross-toolchain@1.0.3': dependencies: - '@napi-rs/lzma': 1.4.3 - '@napi-rs/tar': 0.1.5 - debug: 4.4.1 + '@napi-rs/lzma': 1.4.5 + '@napi-rs/tar': 1.1.0 + debug: 4.4.3 transitivePeerDependencies: - supports-color - '@napi-rs/lzma-android-arm-eabi@1.4.3': + '@napi-rs/lzma-android-arm-eabi@1.4.5': optional: true - '@napi-rs/lzma-android-arm64@1.4.3': + '@napi-rs/lzma-android-arm64@1.4.5': optional: true - '@napi-rs/lzma-darwin-arm64@1.4.3': + '@napi-rs/lzma-darwin-arm64@1.4.5': optional: true - '@napi-rs/lzma-darwin-x64@1.4.3': + '@napi-rs/lzma-darwin-x64@1.4.5': optional: true - '@napi-rs/lzma-freebsd-x64@1.4.3': + '@napi-rs/lzma-freebsd-x64@1.4.5': optional: true - '@napi-rs/lzma-linux-arm-gnueabihf@1.4.3': + '@napi-rs/lzma-linux-arm-gnueabihf@1.4.5': optional: true - '@napi-rs/lzma-linux-arm64-gnu@1.4.3': + '@napi-rs/lzma-linux-arm64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-arm64-musl@1.4.3': + '@napi-rs/lzma-linux-arm64-musl@1.4.5': optional: true - '@napi-rs/lzma-linux-ppc64-gnu@1.4.3': + '@napi-rs/lzma-linux-ppc64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-riscv64-gnu@1.4.3': + '@napi-rs/lzma-linux-riscv64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-s390x-gnu@1.4.3': + '@napi-rs/lzma-linux-s390x-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-x64-gnu@1.4.3': + '@napi-rs/lzma-linux-x64-gnu@1.4.5': optional: true - '@napi-rs/lzma-linux-x64-musl@1.4.3': + '@napi-rs/lzma-linux-x64-musl@1.4.5': optional: true - '@napi-rs/lzma-wasm32-wasi@1.4.3': + '@napi-rs/lzma-wasm32-wasi@1.4.5': dependencies: - '@napi-rs/wasm-runtime': 0.2.12 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/lzma-win32-arm64-msvc@1.4.3': + '@napi-rs/lzma-win32-arm64-msvc@1.4.5': optional: true - '@napi-rs/lzma-win32-ia32-msvc@1.4.3': + '@napi-rs/lzma-win32-ia32-msvc@1.4.5': optional: true - '@napi-rs/lzma-win32-x64-msvc@1.4.3': + '@napi-rs/lzma-win32-x64-msvc@1.4.5': optional: true - '@napi-rs/lzma@1.4.3': + '@napi-rs/lzma@1.4.5': optionalDependencies: - '@napi-rs/lzma-android-arm-eabi': 1.4.3 - '@napi-rs/lzma-android-arm64': 1.4.3 - '@napi-rs/lzma-darwin-arm64': 1.4.3 - '@napi-rs/lzma-darwin-x64': 1.4.3 - '@napi-rs/lzma-freebsd-x64': 1.4.3 - '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.3 - '@napi-rs/lzma-linux-arm64-gnu': 1.4.3 - '@napi-rs/lzma-linux-arm64-musl': 1.4.3 - '@napi-rs/lzma-linux-ppc64-gnu': 1.4.3 - '@napi-rs/lzma-linux-riscv64-gnu': 1.4.3 - '@napi-rs/lzma-linux-s390x-gnu': 1.4.3 - '@napi-rs/lzma-linux-x64-gnu': 1.4.3 - '@napi-rs/lzma-linux-x64-musl': 1.4.3 - '@napi-rs/lzma-wasm32-wasi': 1.4.3 - '@napi-rs/lzma-win32-arm64-msvc': 1.4.3 - '@napi-rs/lzma-win32-ia32-msvc': 1.4.3 - '@napi-rs/lzma-win32-x64-msvc': 1.4.3 + '@napi-rs/lzma-android-arm-eabi': 1.4.5 + '@napi-rs/lzma-android-arm64': 1.4.5 + '@napi-rs/lzma-darwin-arm64': 1.4.5 + '@napi-rs/lzma-darwin-x64': 1.4.5 + '@napi-rs/lzma-freebsd-x64': 1.4.5 + '@napi-rs/lzma-linux-arm-gnueabihf': 1.4.5 + '@napi-rs/lzma-linux-arm64-gnu': 1.4.5 + '@napi-rs/lzma-linux-arm64-musl': 1.4.5 + '@napi-rs/lzma-linux-ppc64-gnu': 1.4.5 + '@napi-rs/lzma-linux-riscv64-gnu': 1.4.5 + '@napi-rs/lzma-linux-s390x-gnu': 1.4.5 + '@napi-rs/lzma-linux-x64-gnu': 1.4.5 + '@napi-rs/lzma-linux-x64-musl': 1.4.5 + '@napi-rs/lzma-wasm32-wasi': 1.4.5 + '@napi-rs/lzma-win32-arm64-msvc': 1.4.5 + '@napi-rs/lzma-win32-ia32-msvc': 1.4.5 + '@napi-rs/lzma-win32-x64-msvc': 1.4.5 - '@napi-rs/tar-android-arm-eabi@0.1.5': + '@napi-rs/tar-android-arm-eabi@1.1.0': optional: true - '@napi-rs/tar-android-arm64@0.1.5': + '@napi-rs/tar-android-arm64@1.1.0': optional: true - '@napi-rs/tar-darwin-arm64@0.1.5': + '@napi-rs/tar-darwin-arm64@1.1.0': optional: true - '@napi-rs/tar-darwin-x64@0.1.5': + '@napi-rs/tar-darwin-x64@1.1.0': optional: true - '@napi-rs/tar-freebsd-x64@0.1.5': + '@napi-rs/tar-freebsd-x64@1.1.0': optional: true - '@napi-rs/tar-linux-arm-gnueabihf@0.1.5': + '@napi-rs/tar-linux-arm-gnueabihf@1.1.0': optional: true - '@napi-rs/tar-linux-arm64-gnu@0.1.5': + '@napi-rs/tar-linux-arm64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-arm64-musl@0.1.5': + '@napi-rs/tar-linux-arm64-musl@1.1.0': optional: true - '@napi-rs/tar-linux-ppc64-gnu@0.1.5': + '@napi-rs/tar-linux-ppc64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-s390x-gnu@0.1.5': + '@napi-rs/tar-linux-s390x-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-x64-gnu@0.1.5': + '@napi-rs/tar-linux-x64-gnu@1.1.0': optional: true - '@napi-rs/tar-linux-x64-musl@0.1.5': + '@napi-rs/tar-linux-x64-musl@1.1.0': optional: true - '@napi-rs/tar-wasm32-wasi@0.1.5': + '@napi-rs/tar-wasm32-wasi@1.1.0': dependencies: - '@napi-rs/wasm-runtime': 0.2.12 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/tar-win32-arm64-msvc@0.1.5': + '@napi-rs/tar-win32-arm64-msvc@1.1.0': optional: true - '@napi-rs/tar-win32-ia32-msvc@0.1.5': + '@napi-rs/tar-win32-ia32-msvc@1.1.0': optional: true - '@napi-rs/tar-win32-x64-msvc@0.1.5': + '@napi-rs/tar-win32-x64-msvc@1.1.0': optional: true - '@napi-rs/tar@0.1.5': + '@napi-rs/tar@1.1.0': optionalDependencies: - '@napi-rs/tar-android-arm-eabi': 0.1.5 - '@napi-rs/tar-android-arm64': 0.1.5 - '@napi-rs/tar-darwin-arm64': 0.1.5 - '@napi-rs/tar-darwin-x64': 0.1.5 - '@napi-rs/tar-freebsd-x64': 0.1.5 - '@napi-rs/tar-linux-arm-gnueabihf': 0.1.5 - '@napi-rs/tar-linux-arm64-gnu': 0.1.5 - '@napi-rs/tar-linux-arm64-musl': 0.1.5 - '@napi-rs/tar-linux-ppc64-gnu': 0.1.5 - '@napi-rs/tar-linux-s390x-gnu': 0.1.5 - '@napi-rs/tar-linux-x64-gnu': 0.1.5 - '@napi-rs/tar-linux-x64-musl': 0.1.5 - '@napi-rs/tar-wasm32-wasi': 0.1.5 - '@napi-rs/tar-win32-arm64-msvc': 0.1.5 - '@napi-rs/tar-win32-ia32-msvc': 0.1.5 - '@napi-rs/tar-win32-x64-msvc': 0.1.5 + '@napi-rs/tar-android-arm-eabi': 1.1.0 + '@napi-rs/tar-android-arm64': 1.1.0 + '@napi-rs/tar-darwin-arm64': 1.1.0 + '@napi-rs/tar-darwin-x64': 1.1.0 + '@napi-rs/tar-freebsd-x64': 1.1.0 + '@napi-rs/tar-linux-arm-gnueabihf': 1.1.0 + '@napi-rs/tar-linux-arm64-gnu': 1.1.0 + '@napi-rs/tar-linux-arm64-musl': 1.1.0 + '@napi-rs/tar-linux-ppc64-gnu': 1.1.0 + '@napi-rs/tar-linux-s390x-gnu': 1.1.0 + '@napi-rs/tar-linux-x64-gnu': 1.1.0 + '@napi-rs/tar-linux-x64-musl': 1.1.0 + '@napi-rs/tar-wasm32-wasi': 1.1.0 + '@napi-rs/tar-win32-arm64-msvc': 1.1.0 + '@napi-rs/tar-win32-ia32-msvc': 1.1.0 + '@napi-rs/tar-win32-x64-msvc': 1.1.0 - '@napi-rs/wasm-runtime@0.2.12': + '@napi-rs/wasm-runtime@1.0.7': dependencies: - '@emnapi/core': 1.4.5 - '@emnapi/runtime': 1.4.3 - '@tybys/wasm-util': 0.10.0 + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.8.1 + '@tybys/wasm-util': 0.10.1 optional: true - '@napi-rs/wasm-tools-android-arm-eabi@0.0.3': + '@napi-rs/wasm-tools-android-arm-eabi@1.0.1': optional: true - '@napi-rs/wasm-tools-android-arm64@0.0.3': + '@napi-rs/wasm-tools-android-arm64@1.0.1': optional: true - '@napi-rs/wasm-tools-darwin-arm64@0.0.3': + '@napi-rs/wasm-tools-darwin-arm64@1.0.1': optional: true - '@napi-rs/wasm-tools-darwin-x64@0.0.3': + '@napi-rs/wasm-tools-darwin-x64@1.0.1': optional: true - '@napi-rs/wasm-tools-freebsd-x64@0.0.3': + '@napi-rs/wasm-tools-freebsd-x64@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-arm64-gnu@0.0.3': + '@napi-rs/wasm-tools-linux-arm64-gnu@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-arm64-musl@0.0.3': + '@napi-rs/wasm-tools-linux-arm64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-x64-gnu@0.0.3': + '@napi-rs/wasm-tools-linux-x64-gnu@1.0.1': optional: true - '@napi-rs/wasm-tools-linux-x64-musl@0.0.3': + '@napi-rs/wasm-tools-linux-x64-musl@1.0.1': optional: true - '@napi-rs/wasm-tools-wasm32-wasi@0.0.3': + '@napi-rs/wasm-tools-wasm32-wasi@1.0.1': dependencies: - '@napi-rs/wasm-runtime': 0.2.12 + '@napi-rs/wasm-runtime': 1.0.7 optional: true - '@napi-rs/wasm-tools-win32-arm64-msvc@0.0.3': + '@napi-rs/wasm-tools-win32-arm64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools-win32-ia32-msvc@0.0.3': + '@napi-rs/wasm-tools-win32-ia32-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools-win32-x64-msvc@0.0.3': + '@napi-rs/wasm-tools-win32-x64-msvc@1.0.1': optional: true - '@napi-rs/wasm-tools@0.0.3': + '@napi-rs/wasm-tools@1.0.1': optionalDependencies: - '@napi-rs/wasm-tools-android-arm-eabi': 0.0.3 - '@napi-rs/wasm-tools-android-arm64': 0.0.3 - '@napi-rs/wasm-tools-darwin-arm64': 0.0.3 - '@napi-rs/wasm-tools-darwin-x64': 0.0.3 - '@napi-rs/wasm-tools-freebsd-x64': 0.0.3 - '@napi-rs/wasm-tools-linux-arm64-gnu': 0.0.3 - '@napi-rs/wasm-tools-linux-arm64-musl': 0.0.3 - '@napi-rs/wasm-tools-linux-x64-gnu': 0.0.3 - '@napi-rs/wasm-tools-linux-x64-musl': 0.0.3 - '@napi-rs/wasm-tools-wasm32-wasi': 0.0.3 - '@napi-rs/wasm-tools-win32-arm64-msvc': 0.0.3 - '@napi-rs/wasm-tools-win32-ia32-msvc': 0.0.3 - '@napi-rs/wasm-tools-win32-x64-msvc': 0.0.3 + '@napi-rs/wasm-tools-android-arm-eabi': 1.0.1 + '@napi-rs/wasm-tools-android-arm64': 1.0.1 + '@napi-rs/wasm-tools-darwin-arm64': 1.0.1 + '@napi-rs/wasm-tools-darwin-x64': 1.0.1 + '@napi-rs/wasm-tools-freebsd-x64': 1.0.1 + '@napi-rs/wasm-tools-linux-arm64-gnu': 1.0.1 + '@napi-rs/wasm-tools-linux-arm64-musl': 1.0.1 + '@napi-rs/wasm-tools-linux-x64-gnu': 1.0.1 + '@napi-rs/wasm-tools-linux-x64-musl': 1.0.1 + '@napi-rs/wasm-tools-wasm32-wasi': 1.0.1 + '@napi-rs/wasm-tools-win32-arm64-msvc': 1.0.1 + '@napi-rs/wasm-tools-win32-ia32-msvc': 1.0.1 + '@napi-rs/wasm-tools-win32-x64-msvc': 1.0.1 '@nodelib/fs.scandir@2.1.5': dependencies: @@ -3319,128 +3578,155 @@ 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.52.4)': + '@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.52.4 + rollup: 4.55.2 - '@rollup/plugin-typescript@12.1.4(rollup@4.52.4)(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.52.4) + '@rollup/pluginutils': 5.2.0(rollup@4.55.2) resolve: 1.22.10 typescript: 5.8.3 optionalDependencies: - rollup: 4.52.4 + rollup: 4.55.2 tslib: 2.8.1 - '@rollup/pluginutils@5.2.0(rollup@4.52.4)': + '@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.52.4 + rollup: 4.55.2 - '@rollup/rollup-android-arm-eabi@4.52.4': + '@rollup/rollup-android-arm-eabi@4.55.2': optional: true - '@rollup/rollup-android-arm64@4.52.4': + '@rollup/rollup-android-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-arm64@4.52.4': + '@rollup/rollup-darwin-arm64@4.55.2': optional: true - '@rollup/rollup-darwin-x64@4.52.4': + '@rollup/rollup-darwin-x64@4.55.2': optional: true - '@rollup/rollup-freebsd-arm64@4.52.4': + '@rollup/rollup-freebsd-arm64@4.55.2': optional: true - '@rollup/rollup-freebsd-x64@4.52.4': + '@rollup/rollup-freebsd-x64@4.55.2': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.52.4': + '@rollup/rollup-linux-arm-gnueabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.52.4': + '@rollup/rollup-linux-arm-musleabihf@4.55.2': optional: true - '@rollup/rollup-linux-arm64-gnu@4.52.4': + '@rollup/rollup-linux-arm64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-arm64-musl@4.52.4': + '@rollup/rollup-linux-arm64-musl@4.55.2': optional: true - '@rollup/rollup-linux-loong64-gnu@4.52.4': + '@rollup/rollup-linux-loong64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.52.4': + '@rollup/rollup-linux-loong64-musl@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.52.4': + '@rollup/rollup-linux-ppc64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-riscv64-musl@4.52.4': + '@rollup/rollup-linux-ppc64-musl@4.55.2': optional: true - '@rollup/rollup-linux-s390x-gnu@4.52.4': + '@rollup/rollup-linux-riscv64-gnu@4.55.2': optional: true - '@rollup/rollup-linux-x64-gnu@4.52.4': + '@rollup/rollup-linux-riscv64-musl@4.55.2': optional: true - '@rollup/rollup-linux-x64-musl@4.52.4': + '@rollup/rollup-linux-s390x-gnu@4.55.2': optional: true - '@rollup/rollup-openharmony-arm64@4.52.4': + '@rollup/rollup-linux-x64-gnu@4.55.2': optional: true - '@rollup/rollup-win32-arm64-msvc@4.52.4': + '@rollup/rollup-linux-x64-musl@4.55.2': optional: true - '@rollup/rollup-win32-ia32-msvc@4.52.4': + '@rollup/rollup-openbsd-x64@4.55.2': optional: true - '@rollup/rollup-win32-x64-gnu@4.52.4': + '@rollup/rollup-openharmony-arm64@4.55.2': optional: true - '@rollup/rollup-win32-x64-msvc@4.52.4': + '@rollup/rollup-win32-arm64-msvc@4.55.2': optional: true + '@rollup/rollup-win32-ia32-msvc@4.55.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.55.2': + optional: true + + '@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)': dependencies: acorn: 8.15.0 - '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)))(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))': + '@sveltejs/vite-plugin-svelte-inspector@5.0.0(@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)))(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))': dependencies: - '@sveltejs/vite-plugin-svelte': 6.0.0(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)) - debug: 4.4.1 + '@sveltejs/vite-plugin-svelte': 6.0.0(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)) + debug: 4.4.3 svelte: 5.35.6 - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) transitivePeerDependencies: - supports-color - '@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))': + '@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))': dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)))(svelte@5.35.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)) - debug: 4.4.1 + '@sveltejs/vite-plugin-svelte-inspector': 5.0.0(@sveltejs/vite-plugin-svelte@6.0.0(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)))(svelte@5.35.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)) + debug: 4.4.3 deepmerge: 4.3.1 kleur: 4.1.5 - magic-string: 0.30.19 + magic-string: 0.30.21 svelte: 5.35.6 - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) - vitefu: 1.1.1(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) + vitefu: 1.1.1(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)) transitivePeerDependencies: - supports-color - '@tybys/wasm-util@0.10.0': + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 optional: true @@ -3460,9 +3746,9 @@ snapshots: '@types/json-schema@7.0.15': {} - '@types/node@22.15.32': + '@types/node@24.10.0': dependencies: - undici-types: 6.21.0 + undici-types: 7.16.0 '@typescript-eslint/eslint-plugin@8.34.1(@typescript-eslint/parser@8.34.1(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3)': dependencies: @@ -3487,7 +3773,7 @@ snapshots: '@typescript-eslint/types': 8.34.1 '@typescript-eslint/typescript-estree': 8.34.1(typescript@5.8.3) '@typescript-eslint/visitor-keys': 8.34.1 - debug: 4.4.1 + debug: 4.4.3 eslint: 9.29.0(jiti@2.4.2) typescript: 5.8.3 transitivePeerDependencies: @@ -3497,7 +3783,7 @@ snapshots: dependencies: '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.8.3) '@typescript-eslint/types': 8.34.1 - debug: 4.4.1 + debug: 4.4.3 typescript: 5.8.3 transitivePeerDependencies: - supports-color @@ -3515,7 +3801,7 @@ snapshots: dependencies: '@typescript-eslint/typescript-estree': 8.34.1(typescript@5.8.3) '@typescript-eslint/utils': 8.34.1(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3) - debug: 4.4.1 + debug: 4.4.3 eslint: 9.29.0(jiti@2.4.2) ts-api-utils: 2.1.0(typescript@5.8.3) typescript: 5.8.3 @@ -3530,11 +3816,11 @@ snapshots: '@typescript-eslint/tsconfig-utils': 8.34.1(typescript@5.8.3) '@typescript-eslint/types': 8.34.1 '@typescript-eslint/visitor-keys': 8.34.1 - debug: 4.4.1 + debug: 4.4.3 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: @@ -3556,13 +3842,13 @@ snapshots: '@typescript-eslint/types': 8.34.1 eslint-visitor-keys: 4.2.1 - '@unocss/astro@66.3.3(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3))': + '@unocss/astro@66.3.3(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3))': dependencies: '@unocss/core': 66.3.3 '@unocss/reset': 66.3.3 - '@unocss/vite': 66.3.3(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) + '@unocss/vite': 66.3.3(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) optionalDependencies: - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) transitivePeerDependencies: - vue @@ -3576,7 +3862,7 @@ snapshots: chokidar: 3.6.0 colorette: 2.0.20 consola: 3.4.2 - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 2.0.3 perfect-debounce: 1.0.0 tinyglobby: 0.2.15 @@ -3675,7 +3961,7 @@ snapshots: '@unocss/rule-utils@66.3.3': dependencies: '@unocss/core': 66.3.3 - magic-string: 0.30.19 + magic-string: 0.30.21 '@unocss/transformer-attributify-jsx@66.3.3': dependencies: @@ -3695,66 +3981,63 @@ snapshots: dependencies: '@unocss/core': 66.3.3 - '@unocss/vite@66.3.3(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3))': + '@unocss/vite@66.3.3(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3))': dependencies: '@ampproject/remapping': 2.3.0 '@unocss/config': 66.3.3 '@unocss/core': 66.3.3 '@unocss/inspector': 66.3.3(vue@3.5.17(typescript@5.8.3)) chokidar: 3.6.0 - magic-string: 0.30.19 + magic-string: 0.30.21 pathe: 2.0.3 tinyglobby: 0.2.15 unplugin-utils: 0.2.4 - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) transitivePeerDependencies: - vue - '@vitest/expect@3.2.4': + '@vitest/expect@4.0.6': dependencies: + '@standard-schema/spec': 1.0.0 '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.0 - tinyrainbow: 2.0.0 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + chai: 6.2.0 + tinyrainbow: 3.0.3 - '@vitest/mocker@3.2.4(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))': + '@vitest/mocker@4.0.6(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))': dependencies: - '@vitest/spy': 3.2.4 + '@vitest/spy': 4.0.6 estree-walker: 3.0.3 - magic-string: 0.30.19 + magic-string: 0.30.21 optionalDependencies: - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) - '@vitest/pretty-format@3.2.4': + '@vitest/pretty-format@4.0.6': dependencies: - tinyrainbow: 2.0.0 + tinyrainbow: 3.0.3 - '@vitest/runner@3.2.4': + '@vitest/runner@4.0.6': dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.0.0 - - '@vitest/snapshot@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.19 + '@vitest/utils': 4.0.6 pathe: 2.0.3 - '@vitest/spy@3.2.4': + '@vitest/snapshot@4.0.6': dependencies: - tinyspy: 4.0.3 + '@vitest/pretty-format': 4.0.6 + magic-string: 0.30.21 + pathe: 2.0.3 - '@vitest/utils@3.2.4': + '@vitest/spy@4.0.6': {} + + '@vitest/utils@4.0.6': dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.1.4 - tinyrainbow: 2.0.0 + '@vitest/pretty-format': 4.0.6 + tinyrainbow: 3.0.3 '@vue/compiler-core@3.5.17': dependencies: - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.6 '@vue/shared': 3.5.17 entities: 4.5.0 estree-walker: 2.0.2 @@ -3767,13 +4050,13 @@ snapshots: '@vue/compiler-sfc@3.5.17': dependencies: - '@babel/parser': 7.28.4 + '@babel/parser': 7.28.6 '@vue/compiler-core': 3.5.17 '@vue/compiler-dom': 3.5.17 '@vue/compiler-ssr': 3.5.17 '@vue/shared': 3.5.17 estree-walker: 2.0.2 - magic-string: 0.30.19 + magic-string: 0.30.21 postcss: 8.5.6 source-map-js: 1.2.1 @@ -3796,7 +4079,7 @@ snapshots: '@vue/reactivity': 3.5.17 '@vue/runtime-core': 3.5.17 '@vue/shared': 3.5.17 - csstype: 3.1.3 + csstype: 3.2.3 '@vue/server-renderer@3.5.17(vue@3.5.17(typescript@5.8.3))': dependencies: @@ -3823,10 +4106,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ansi-escapes@4.3.2: - dependencies: - type-fest: 0.21.3 - ansi-regex@5.0.1: {} ansi-styles@4.3.0: @@ -3842,12 +4121,6 @@ snapshots: aria-query@5.3.2: {} - as-table@1.0.55: - dependencies: - printable-characters: 1.0.42 - - assertion-error@2.0.1: {} - axobject-query@4.1.0: {} balanced-match@3.0.1: {} @@ -3872,22 +4145,14 @@ snapshots: callsites@3.1.0: {} - chai@5.2.0: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.1.4 - pathval: 2.0.0 + chai@6.2.0: {} chalk@4.1.2: dependencies: ansi-styles: 4.3.0 supports-color: 7.2.0 - chardet@0.7.0: {} - - check-error@2.1.1: {} + chardet@2.1.1: {} chokidar@3.6.0: dependencies: @@ -3915,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: {} @@ -3935,7 +4190,7 @@ snapshots: consola@3.4.2: {} - cookie@0.7.2: {} + cookie@1.1.1: {} cross-env@10.1.0: dependencies: @@ -3953,16 +4208,12 @@ snapshots: mdn-data: 2.12.2 source-map-js: 1.2.1 - csstype@3.1.3: {} + csstype@3.2.3: {} - data-uri-to-buffer@2.0.2: {} - - debug@4.4.1: + debug@4.4.3: dependencies: ms: 2.1.3 - deep-eql@5.0.2: {} - deep-is@0.1.4: {} deepmerge@4.3.1: {} @@ -3971,16 +4222,22 @@ snapshots: destr@2.0.5: {} - detect-libc@2.0.4: {} + detect-libc@2.1.2: {} duplexer@0.1.2: {} + emnapi@1.7.1: {} + emoji-regex@8.0.0: {} entities@4.5.0: {} + error-stack-parser-es@1.0.5: {} + es-module-lexer@1.7.0: {} + es-toolkit@1.42.0: {} + esbuild@0.25.4: optionalDependencies: '@esbuild/aix-ppc64': 0.25.4 @@ -4009,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)): @@ -4046,7 +4332,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.1 + debug: 4.4.3 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -4102,16 +4388,10 @@ snapshots: exit-hook@2.2.1: {} - expect-type@1.2.1: {} + expect-type@1.2.2: {} exsolve@1.0.7: {} - external-editor@3.1.0: - dependencies: - chardet: 0.7.0 - iconv-lite: 0.4.24 - tmp: 0.2.5 - fast-content-type-parse@3.0.0: {} fast-deep-equal@3.1.3: {} @@ -4149,12 +4429,6 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - find-up@7.0.0: - dependencies: - locate-path: 7.2.0 - path-exists: 5.0.0 - unicorn-magic: 0.1.0 - flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -4167,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 @@ -4186,7 +4455,7 @@ snapshots: globals@15.15.0: {} - globals@16.2.0: {} + globals@17.0.0: {} graphemer@1.4.0: {} @@ -4200,7 +4469,7 @@ snapshots: dependencies: function-bind: 1.1.2 - iconv-lite@0.4.24: + iconv-lite@0.7.0: dependencies: safer-buffer: 2.1.2 @@ -4215,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 @@ -4243,9 +4510,7 @@ snapshots: jiti@2.4.2: {} - js-tokens@9.0.1: {} - - js-yaml@4.1.0: + js-yaml@4.1.1: dependencies: argparse: 2.0.1 @@ -4280,17 +4545,9 @@ snapshots: dependencies: p-locate: 5.0.0 - locate-path@7.2.0: - dependencies: - p-locate: 6.0.0 - - lodash-es@4.17.21: {} - lodash.merge@4.6.2: {} - loupe@3.1.4: {} - - magic-string@0.30.19: + magic-string@0.30.21: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -4305,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 @@ -4342,8 +4599,6 @@ snapshots: ms@2.1.3: {} - mustache@4.2.0: {} - mute-stream@2.0.0: {} nanoid@3.3.11: {} @@ -4360,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 @@ -4375,18 +4628,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 - p-limit@4.0.0: - dependencies: - yocto-queue: 1.2.1 - p-locate@5.0.0: dependencies: p-limit: 3.1.0 - p-locate@6.0.0: - dependencies: - p-limit: 4.0.0 - package-manager-detector@1.3.0: {} parent-module@1.0.1: @@ -4395,8 +4640,6 @@ snapshots: path-exists@4.0.0: {} - path-exists@5.0.0: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -4405,8 +4648,6 @@ snapshots: pathe@2.0.3: {} - pathval@2.0.0: {} - perfect-debounce@1.0.0: {} picocolors@1.1.1: {} @@ -4435,9 +4676,7 @@ snapshots: prelude-ls@1.2.1: {} - prettier@3.5.3: {} - - printable-characters@1.0.42: {} + prettier@3.6.2: {} punycode@2.3.1: {} @@ -4465,32 +4704,35 @@ snapshots: reusify@1.1.0: {} - rollup@4.52.4: + rollup@4.55.2: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.52.4 - '@rollup/rollup-android-arm64': 4.52.4 - '@rollup/rollup-darwin-arm64': 4.52.4 - '@rollup/rollup-darwin-x64': 4.52.4 - '@rollup/rollup-freebsd-arm64': 4.52.4 - '@rollup/rollup-freebsd-x64': 4.52.4 - '@rollup/rollup-linux-arm-gnueabihf': 4.52.4 - '@rollup/rollup-linux-arm-musleabihf': 4.52.4 - '@rollup/rollup-linux-arm64-gnu': 4.52.4 - '@rollup/rollup-linux-arm64-musl': 4.52.4 - '@rollup/rollup-linux-loong64-gnu': 4.52.4 - '@rollup/rollup-linux-ppc64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-gnu': 4.52.4 - '@rollup/rollup-linux-riscv64-musl': 4.52.4 - '@rollup/rollup-linux-s390x-gnu': 4.52.4 - '@rollup/rollup-linux-x64-gnu': 4.52.4 - '@rollup/rollup-linux-x64-musl': 4.52.4 - '@rollup/rollup-openharmony-arm64': 4.52.4 - '@rollup/rollup-win32-arm64-msvc': 4.52.4 - '@rollup/rollup-win32-ia32-msvc': 4.52.4 - '@rollup/rollup-win32-x64-gnu': 4.52.4 - '@rollup/rollup-win32-x64-msvc': 4.52.4 + '@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: @@ -4505,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: @@ -4547,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 @@ -4570,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: {} @@ -4591,9 +4829,7 @@ snapshots: strip-json-comments@3.1.1: {} - strip-literal@3.0.0: - dependencies: - js-tokens: 9.0.1 + supports-color@10.2.2: {} supports-color@7.2.0: dependencies: @@ -4615,7 +4851,7 @@ snapshots: esrap: 2.1.0 is-reference: 3.0.3 locate-character: 3.0.0 - magic-string: 0.30.19 + magic-string: 0.30.21 zimmerframe: 1.1.2 terser@5.43.1: @@ -4636,13 +4872,7 @@ snapshots: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.3: {} - - tmp@0.2.5: {} + tinyrainbow@3.0.3: {} to-regex-range@5.0.1: dependencies: @@ -4662,8 +4892,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-fest@0.21.3: {} - typescript-eslint@8.34.1(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.34.1(@typescript-eslint/parser@8.34.1(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3))(eslint@9.29.0(jiti@2.4.2))(typescript@5.8.3) @@ -4685,27 +4913,19 @@ snapshots: jiti: 2.4.2 quansync: 0.2.10 - undici-types@6.21.0: {} + 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 - - unicorn-magic@0.1.0: {} universal-user-agent@7.0.3: {} - unocss@66.3.3(postcss@8.5.6)(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)): + unocss@66.3.3(postcss@8.5.6)(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)): dependencies: - '@unocss/astro': 66.3.3(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) + '@unocss/astro': 66.3.3(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) '@unocss/cli': 66.3.3 '@unocss/core': 66.3.3 '@unocss/postcss': 66.3.3(postcss@8.5.6) @@ -4723,9 +4943,9 @@ snapshots: '@unocss/transformer-compile-class': 66.3.3 '@unocss/transformer-directives': 66.3.3 '@unocss/transformer-variant-group': 66.3.3 - '@unocss/vite': 66.3.3(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) + '@unocss/vite': 66.3.3(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1))(vue@3.5.17(typescript@5.8.3)) optionalDependencies: - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) transitivePeerDependencies: - postcss - supports-color @@ -4740,72 +4960,48 @@ snapshots: dependencies: punycode: 2.3.1 - vite-node@3.2.4(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1): - dependencies: - cac: 6.7.14 - debug: 4.4.1 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1): + vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1): dependencies: esbuild: 0.25.4 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.52.4 + rollup: 4.55.2 tinyglobby: 0.2.15 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 fsevents: 2.3.3 jiti: 2.4.2 terser: 5.43.1 - vitefu@1.1.1(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)): + vitefu@1.1.1(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)): optionalDependencies: - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) - vitest@3.2.4(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1): + vitest@4.0.6(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1): dependencies: - '@types/chai': 5.2.2 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.2.0 - debug: 4.4.1 - expect-type: 1.2.1 - magic-string: 0.30.19 + '@vitest/expect': 4.0.6 + '@vitest/mocker': 4.0.6(vite@7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1)) + '@vitest/pretty-format': 4.0.6 + '@vitest/runner': 4.0.6 + '@vitest/snapshot': 4.0.6 + '@vitest/spy': 4.0.6 + '@vitest/utils': 4.0.6 + debug: 4.4.3 + es-module-lexer: 1.7.0 + expect-type: 1.2.2 + magic-string: 0.30.21 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.1.5(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) - vite-node: 3.2.4(@types/node@22.15.32)(jiti@2.4.2)(terser@5.43.1) + tinyrainbow: 3.0.3 + vite: 7.1.11(@types/node@24.10.0)(jiti@2.4.2)(terser@5.43.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 22.15.32 + '@types/node': 24.10.0 transitivePeerDependencies: - jiti - less @@ -4834,8 +5030,6 @@ snapshots: optionalDependencies: typescript: 5.8.3 - wasm-sjlj@1.0.6: {} - which@2.0.2: dependencies: isexe: 2.0.0 @@ -4847,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: @@ -4881,16 +5075,21 @@ snapshots: yocto-queue@0.1.0: {} - yocto-queue@1.2.1: {} + yoctocolors-cjs@2.1.3: {} - yoctocolors-cjs@2.1.2: {} - - 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: {} diff --git a/renovate.json b/renovate.json index 016c0c807..3f55df977 100644 --- a/renovate.json +++ b/renovate.json @@ -29,6 +29,11 @@ "https://github.com/microsoft/windows-rs", "https://github.com/wravery/webview2-rs" ] + }, + { + "description": "Group worker-rs crates", + "groupName": "worker-rs crates", + "matchSourceUrls": ["https://github.com/cloudflare/workers-rs"] } ], "postUpdateOptions": ["pnpmDedupe"]