Merge branch 'feat/mobile-multi-window' into feat/mobile-file-association

This commit is contained in:
Lucas Nogueira 2025-12-28 09:32:18 -03:00
commit afb226855b
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7
101 changed files with 1232 additions and 1124 deletions

View File

@ -1,5 +0,0 @@
---
"@tauri-apps/api": patch:bug
---
Fix `addPluginListener` fallback added in https://github.com/tauri-apps/tauri/pull/14132 didn't work properly

View File

@ -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.

View File

@ -1,8 +0,0 @@
---
"tauri": patch:perf
"tauri-cli": patch:perf
"tauri-bundler": patch:perf
"@tauri-apps/cli": patch:perf
---
refactor: remove needless collect. No user facing changes.

View File

@ -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.

View File

@ -1,5 +0,0 @@
---
"tauri-bundler": patch:deps
---
Updated NSIS from 3.8 to 3.11

View File

@ -0,0 +1,5 @@
---
tauri: patch:bug
---
`WindowConfig::focus` is set to `false` in `WindowConfig::default()`

View File

@ -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. - 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: - 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. - 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 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)`. - 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. - Provide detailed description of the bug in the PR, or link to an issue that does.

242
Cargo.lock generated
View File

@ -1083,7 +1083,7 @@ dependencies = [
"serde_json", "serde_json",
"textwrap", "textwrap",
"thiserror 2.0.12", "thiserror 2.0.12",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"ureq", "ureq",
"which", "which",
"windows 0.61.1", "windows 0.61.1",
@ -1120,7 +1120,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77" checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
dependencies = [ dependencies = [
"serde", "serde",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
] ]
[[package]] [[package]]
@ -1319,7 +1319,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c" checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [ dependencies = [
"lazy_static", "lazy_static",
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -2219,7 +2219,7 @@ dependencies = [
"cc", "cc",
"memchr", "memchr",
"rustc_version", "rustc_version",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"vswhom", "vswhom",
"winreg 0.55.0", "winreg 0.55.0",
] ]
@ -3105,7 +3105,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http 0.2.12", "http 0.2.12",
"indexmap 2.7.0", "indexmap 2.11.4",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -3124,7 +3124,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"http 1.3.1", "http 1.3.1",
"indexmap 2.7.0", "indexmap 2.11.4",
"slab", "slab",
"tokio", "tokio",
"tokio-util", "tokio-util",
@ -3177,9 +3177,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.15.2" version = "0.16.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
[[package]] [[package]]
name = "heck" name = "heck"
@ -3467,9 +3467,9 @@ dependencies = [
[[package]] [[package]]
name = "ico" name = "ico"
version = "0.4.0" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc50b891e4acf8fe0e71ef88ec43ad82ee07b3810ad09de10f1d01f072ed4b98" checksum = "3e795dff5605e0f04bff85ca41b51a96b83e80b281e96231bcaaf1ac35103371"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"png", "png",
@ -3722,13 +3722,14 @@ dependencies = [
[[package]] [[package]]
name = "indexmap" name = "indexmap"
version = "2.7.0" version = "2.11.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" checksum = "4b0f83760fb341a774ed326568e19f5a863af4a952def8c39f9ab92fd95b88e5"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.15.2", "hashbrown 0.16.1",
"serde", "serde",
"serde_core",
] ]
[[package]] [[package]]
@ -3968,9 +3969,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.77" version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" checksum = "464a3709c7f55f1f721e5389aa6ea4e3bc6aba669353300af094b29ffbdde1d8"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"wasm-bindgen", "wasm-bindgen",
@ -4233,7 +4234,7 @@ checksum = "02cb977175687f33fa4afa0c95c112b987ea1443e5a51c8f8ff27dc618270cc2"
dependencies = [ dependencies = [
"cssparser", "cssparser",
"html5ever", "html5ever",
"indexmap 2.7.0", "indexmap 2.11.4",
"selectors", "selectors",
] ]
@ -4891,11 +4892,10 @@ dependencies = [
[[package]] [[package]]
name = "num-bigint-dig" name = "num-bigint-dig"
version = "0.8.4" version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" checksum = "e661dda6640fad38e827a6d4a310ff4763082116fe217f279885c97f511bb0b7"
dependencies = [ dependencies = [
"byteorder",
"lazy_static", "lazy_static",
"libm", "libm",
"num-integer", "num-integer",
@ -5287,7 +5287,7 @@ dependencies = [
"crc32fast", "crc32fast",
"flate2", "flate2",
"hashbrown 0.14.5", "hashbrown 0.14.5",
"indexmap 2.7.0", "indexmap 2.11.4",
"memchr", "memchr",
"ruzstd", "ruzstd",
] ]
@ -6117,7 +6117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016" checksum = "42cf17e9a1800f5f396bc67d193dc9411b59012a5876445ef450d449881e1016"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"indexmap 2.7.0", "indexmap 2.11.4",
"quick-xml", "quick-xml",
"serde", "serde",
"time", "time",
@ -7551,10 +7551,11 @@ checksum = "a3f0bf26fd526d2a95683cd0f87bf103b8539e2ca1ef48ce002d67aad59aa0b4"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.219" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [ dependencies = [
"serde_core",
"serde_derive", "serde_derive",
] ]
@ -7603,10 +7604,19 @@ dependencies = [
] ]
[[package]] [[package]]
name = "serde_derive" name = "serde_core"
version = "1.0.219" version = "1.0.228"
source = "registry+https://github.com/rust-lang/crates.io-index" 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 = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -7635,15 +7645,16 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.140" version = "1.0.145"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20068b6e96dc6c9bd23e01df8827e6c7e1f2fddd43c21810382803c136b99373" checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"itoa", "itoa",
"memchr", "memchr",
"ryu", "ryu",
"serde", "serde",
"serde_core",
] ]
[[package]] [[package]]
@ -7678,11 +7689,11 @@ dependencies = [
[[package]] [[package]]
name = "serde_spanned" name = "serde_spanned"
version = "1.0.0" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776"
dependencies = [ dependencies = [
"serde", "serde_core",
] ]
[[package]] [[package]]
@ -7707,7 +7718,7 @@ dependencies = [
"chrono", "chrono",
"hex", "hex",
"indexmap 1.9.3", "indexmap 1.9.3",
"indexmap 2.7.0", "indexmap 2.11.4",
"serde", "serde",
"serde_derive", "serde_derive",
"serde_json", "serde_json",
@ -7733,7 +7744,7 @@ version = "0.9.34+deprecated"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"itoa", "itoa",
"ryu", "ryu",
"serde", "serde",
@ -8527,7 +8538,7 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.9.3" version = "2.9.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
@ -8587,7 +8598,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-build" name = "tauri-build"
version = "2.5.2" version = "2.5.3"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
@ -8603,13 +8614,13 @@ dependencies = [
"tauri-codegen", "tauri-codegen",
"tauri-utils", "tauri-utils",
"tauri-winres", "tauri-winres",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"walkdir", "walkdir",
] ]
[[package]] [[package]]
name = "tauri-bundler" name = "tauri-bundler"
version = "2.7.3" version = "2.7.5"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"ar", "ar",
@ -8655,7 +8666,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-cli" name = "tauri-cli"
version = "2.9.4" version = "2.9.6"
dependencies = [ dependencies = [
"ar", "ar",
"axum", "axum",
@ -8725,8 +8736,8 @@ dependencies = [
"tempfile", "tempfile",
"thiserror 2.0.12", "thiserror 2.0.12",
"tokio", "tokio",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"toml_edit 0.23.2", "toml_edit 0.24.0+spec-1.1.0",
"ureq", "ureq",
"url", "url",
"uuid", "uuid",
@ -8749,7 +8760,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.5.1" version = "2.5.2"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli", "brotli",
@ -8815,7 +8826,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macos-sign" name = "tauri-macos-sign"
version = "2.3.0" version = "2.3.2"
dependencies = [ dependencies = [
"apple-codesign", "apple-codesign",
"chrono", "chrono",
@ -8835,7 +8846,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" name = "tauri-macros"
version = "2.5.1" version = "2.5.2"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@ -8847,7 +8858,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin" name = "tauri-plugin"
version = "2.5.1" version = "2.5.2"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"glob", "glob",
@ -8856,7 +8867,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"tauri-utils", "tauri-utils",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"walkdir", "walkdir",
] ]
@ -8895,7 +8906,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-runtime"
version = "2.9.1" version = "2.9.2"
dependencies = [ dependencies = [
"cookie", "cookie",
"dpi", "dpi",
@ -8918,7 +8929,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime-wry" name = "tauri-runtime-wry"
version = "2.9.1" version = "2.9.3"
dependencies = [ dependencies = [
"gtk", "gtk",
"http 1.3.1", "http 1.3.1",
@ -8969,7 +8980,7 @@ dependencies = [
[[package]] [[package]]
name = "tauri-utils" name = "tauri-utils"
version = "2.8.0" version = "2.8.1"
dependencies = [ dependencies = [
"aes-gcm", "aes-gcm",
"anyhow", "anyhow",
@ -9002,7 +9013,7 @@ dependencies = [
"serialize-to-javascript", "serialize-to-javascript",
"swift-rs", "swift-rs",
"thiserror 2.0.12", "thiserror 2.0.12",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
"url", "url",
"urlpattern", "urlpattern",
"uuid", "uuid",
@ -9016,8 +9027,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c6d9028d41d4de835e3c482c677a8cb88137ac435d6ff9a71f392d4421576c9" checksum = "7c6d9028d41d4de835e3c482c677a8cb88137ac435d6ff9a71f392d4421576c9"
dependencies = [ dependencies = [
"embed-resource", "embed-resource",
"indexmap 2.7.0", "indexmap 2.11.4",
"toml 0.9.4", "toml 0.9.10+spec-1.1.0",
] ]
[[package]] [[package]]
@ -9346,17 +9357,17 @@ dependencies = [
[[package]] [[package]]
name = "toml" name = "toml"
version = "0.9.4" version = "0.9.10+spec-1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "41ae868b5a0f67631c14589f7e250c1ea2c574ee5ba21c6c8dd4b1485705a5a1" checksum = "0825052159284a1a8b4d6c0c86cbc801f2da5afd2b225fa548c72f2e74002f48"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"serde", "serde_core",
"serde_spanned 1.0.0", "serde_spanned 1.0.4",
"toml_datetime 0.7.0", "toml_datetime 0.7.5+spec-1.1.0",
"toml_parser", "toml_parser",
"toml_writer", "toml_writer",
"winnow 0.7.11", "winnow 0.7.14",
] ]
[[package]] [[package]]
@ -9370,11 +9381,11 @@ dependencies = [
[[package]] [[package]]
name = "toml_datetime" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347"
dependencies = [ dependencies = [
"serde", "serde_core",
] ]
[[package]] [[package]]
@ -9383,7 +9394,7 @@ version = "0.19.15"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"toml_datetime 0.6.8", "toml_datetime 0.6.8",
"winnow 0.5.40", "winnow 0.5.40",
] ]
@ -9394,7 +9405,7 @@ version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"toml_datetime 0.6.8", "toml_datetime 0.6.8",
"winnow 0.5.40", "winnow 0.5.40",
] ]
@ -9405,42 +9416,42 @@ version = "0.22.24"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"serde", "serde",
"serde_spanned 0.6.8", "serde_spanned 0.6.8",
"toml_datetime 0.6.8", "toml_datetime 0.6.8",
"winnow 0.7.11", "winnow 0.7.14",
] ]
[[package]] [[package]]
name = "toml_edit" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1dee9dc43ac2aaf7d3b774e2fba5148212bf2bd9374f4e50152ebe9afd03d42" checksum = "8c740b185920170a6d9191122cafef7010bd6270a3824594bff6784c04d7f09e"
dependencies = [ dependencies = [
"indexmap 2.7.0", "indexmap 2.11.4",
"serde", "serde_core",
"serde_spanned 1.0.0", "serde_spanned 1.0.4",
"toml_datetime 0.7.0", "toml_datetime 0.7.5+spec-1.1.0",
"toml_parser", "toml_parser",
"toml_writer", "toml_writer",
"winnow 0.7.11", "winnow 0.7.14",
] ]
[[package]] [[package]]
name = "toml_parser" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "97200572db069e74c512a14117b296ba0a80a30123fbbb5aa1f4a348f639ca30" checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44"
dependencies = [ dependencies = [
"winnow 0.7.11", "winnow 0.7.14",
] ]
[[package]] [[package]]
name = "toml_writer" 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" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607"
[[package]] [[package]]
name = "tower" name = "tower"
@ -10097,35 +10108,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.100" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" checksum = "0d759f433fa64a2d763d1340820e46e111a7a5ab75f993d1852d70b03dbb80fd"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
"rustversion", "rustversion",
"wasm-bindgen-macro", "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", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-futures" name = "wasm-bindgen-futures"
version = "0.4.50" version = "0.4.56"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" checksum = "836d9622d604feee9e5de25ac10e3ea5f2d65b41eac0d9ce72eb5deae707ce7c"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -10136,9 +10134,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-macro"
version = "0.2.100" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" checksum = "48cb0d2638f8baedbc542ed444afc0644a29166f1595371af4fecf8ce1e7eeb3"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@ -10146,22 +10144,22 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.100" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" checksum = "cefb59d5cd5f92d9dcf80e4683949f15ca4b511f4ac0a6e14d4e1ac60c6ecd40"
dependencies = [ dependencies = [
"bumpalo",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.95", "syn 2.0.95",
"wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.100" version = "0.2.106"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" checksum = "cbc538057e648b67f72a982e708d485b2efa771e1ac05fec311f9f63e5800db4"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -10181,9 +10179,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.77" version = "0.3.83"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" checksum = "9b32828d774c412041098d182a8b38b16ea816958e07cf40eec2bc080ae137ac"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -10358,7 +10356,7 @@ version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb"
dependencies = [ dependencies = [
"windows-sys 0.52.0", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -10859,9 +10857,9 @@ dependencies = [
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.7.11" version = "0.7.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74c7b26e3480b707944fc872477815d29a8e429d2f93a1ce000f5fa84a15cbcd" checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -10903,9 +10901,9 @@ dependencies = [
[[package]] [[package]]
name = "worker" name = "worker"
version = "0.6.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f6ac1566a3005b790b974f0621d77431e2a47e5f481276485f5ac0485775de2" checksum = "42c76c5889873a2c309365ad4503810c007d3c25fbb4e9fa9e4e23c4ceb3c7f2"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum", "axum",
@ -10928,31 +10926,15 @@ dependencies = [
"wasm-bindgen-futures", "wasm-bindgen-futures",
"wasm-streams", "wasm-streams",
"web-sys", "web-sys",
"worker-kv",
"worker-macros", "worker-macros",
"worker-sys", "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]] [[package]]
name = "worker-macros" name = "worker-macros"
version = "0.6.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ba7478759843ae3d56dc7ba2445e7a514a5d043eaa98cebac2789f7ab5221ee" checksum = "62c62584d037bad33789a6a5d605b3fccea1c52de9251d06f9d44054170dc612"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"proc-macro2", "proc-macro2",
@ -10966,9 +10948,9 @@ dependencies = [
[[package]] [[package]]
name = "worker-sys" name = "worker-sys"
version = "0.6.0" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb4d7a3273dd584b9526aec77bbcf815c51d1a0e17407b1a390cf5a39b6d4fbd" checksum = "72ddd412fd62c6eeffc1dd85e6ae5960a33b534f44a733df75b6e7519972bc74"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys", "js-sys",
@ -11308,7 +11290,7 @@ dependencies = [
"arbitrary", "arbitrary",
"crc32fast", "crc32fast",
"flate2", "flate2",
"indexmap 2.7.0", "indexmap 2.11.4",
"memchr", "memchr",
"zopfli", "zopfli",
] ]

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## \[2.5.3]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
- Upgraded to `tauri-codegen@2.5.2`
## \[2.5.2] ## \[2.5.2]
### Dependencies ### Dependencies

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-build" name = "tauri-build"
version = "2.5.2" version = "2.5.3"
description = "build time code to pair with https://crates.io/crates/tauri" description = "build time code to pair with https://crates.io/crates/tauri"
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -26,8 +26,8 @@ targets = [
[dependencies] [dependencies]
anyhow = "1" anyhow = "1"
quote = { version = "1", optional = true } quote = { version = "1", optional = true }
tauri-codegen = { version = "2.5.1", path = "../tauri-codegen", optional = true } tauri-codegen = { version = "2.5.2", path = "../tauri-codegen", optional = true }
tauri-utils = { version = "2.8.0", path = "../tauri-utils", features = [ tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [
"build", "build",
"resources", "resources",
] } ] }

View File

@ -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:?}"))?; .with_context(|| format!("Failed to create frameworks output directory at {dest_dir:?}"))?;
for framework in frameworks.iter() { for framework in frameworks.iter() {
if framework.ends_with(".framework") { if framework.ends_with(".framework") {
let src_path = PathBuf::from(framework); let src_path = Path::new(framework);
let src_name = src_path let src_name = src_path
.file_name() .file_name()
.expect("Couldn't get framework filename"); .expect("Couldn't get framework filename");
let dest_path = dest_dir.join(src_name); let dest_path = dest_dir.join(src_name);
copy_dir(&src_path, &dest_path)?; copy_dir(src_path, &dest_path)?;
continue; continue;
} else if framework.ends_with(".dylib") { } else if framework.ends_with(".dylib") {
let src_path = PathBuf::from(framework); let src_path = Path::new(framework);
if !src_path.exists() { if !src_path.exists() {
return Err(anyhow::anyhow!("Library not found: {}", framework)); return Err(anyhow::anyhow!("Library not found: {}", framework));
} }
let src_name = src_path.file_name().expect("Couldn't get library filename"); let src_name = src_path.file_name().expect("Couldn't get library filename");
let dest_path = dest_dir.join(src_name); let dest_path = dest_dir.join(src_name);
copy_file(&src_path, &dest_path)?; copy_file(src_path, &dest_path)?;
continue; continue;
} else if framework.contains('/') { } else if framework.contains('/') {
return Err(anyhow::anyhow!( return Err(anyhow::anyhow!(
@ -192,12 +192,8 @@ fn copy_frameworks(dest_dir: &Path, frameworks: &[String]) -> Result<()> {
continue; continue;
} }
} }
if copy_framework_from(&PathBuf::from("/Library/Frameworks/"), framework, dest_dir)? if copy_framework_from("/Library/Frameworks/".as_ref(), framework, dest_dir)?
|| copy_framework_from( || copy_framework_from("/Network/Library/Frameworks/".as_ref(), framework, dest_dir)?
&PathBuf::from("/Network/Library/Frameworks/"),
framework,
dest_dir,
)?
{ {
continue; continue;
} }

View File

@ -1,5 +1,37 @@
# Changelog # 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] ## \[2.7.3]
### Enhancements ### Enhancements

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-bundler" name = "tauri-bundler"
version = "2.7.3" version = "2.7.5"
authors = [ authors = [
"George Burton <burtonageo@gmail.com>", "George Burton <burtonageo@gmail.com>",
"Tauri Programme within The Commons Conservancy", "Tauri Programme within The Commons Conservancy",
@ -15,7 +15,7 @@ rust-version = "1.77.2"
exclude = ["CHANGELOG.md", "/target", "rustfmt.toml"] exclude = ["CHANGELOG.md", "/target", "rustfmt.toml"]
[dependencies] [dependencies]
tauri-utils = { version = "2.8.0", path = "../tauri-utils", features = [ tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [
"resources", "resources",
] } ] }
image = "0.25" image = "0.25"
@ -59,7 +59,7 @@ features = ["Win32_System_SystemInformation", "Win32_System_Diagnostics_Debug"]
[target."cfg(target_os = \"macos\")".dependencies] [target."cfg(target_os = \"macos\")".dependencies]
icns = { package = "tauri-icns", version = "0.1" } icns = { package = "tauri-icns", version = "0.1" }
time = { version = "0.3", features = ["formatting"] } time = { version = "0.3", features = ["formatting"] }
tauri-macos-sign = { version = "2.3.0", path = "../tauri-macos-sign" } tauri-macos-sign = { version = "2.3.2", path = "../tauri-macos-sign" }
[target."cfg(target_os = \"linux\")".dependencies] [target."cfg(target_os = \"linux\")".dependencies]
heck = "0.5" heck = "0.5"

View File

@ -273,7 +273,7 @@ fn sign_binaries_if_needed(settings: &Settings, target_os: &TargetPlatform) -> c
if matches!(target_os, TargetPlatform::Windows) { if matches!(target_os, TargetPlatform::Windows) {
if settings.windows().can_sign() { if settings.windows().can_sign() {
if settings.no_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(()); return Ok(());
} }

View File

@ -232,7 +232,7 @@ fn prepare_tools(tools_path: &Path, arch: &str, verbose: bool) -> crate::Result<
write_and_make_executable(&apprun, &data)?; write_and_make_executable(&apprun, &data)?;
} }
let linuxdeploy_arch = if arch == "i686" { "i383" } else { arch }; let linuxdeploy_arch = if arch == "i686" { "i386" } else { arch };
let linuxdeploy = tools_path.join(format!("linuxdeploy-{linuxdeploy_arch}.AppImage")); let linuxdeploy = tools_path.join(format!("linuxdeploy-{linuxdeploy_arch}.AppImage"));
if !linuxdeploy.exists() { if !linuxdeploy.exists() {
let data = download(&format!("https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-{linuxdeploy_arch}.AppImage"))?; let data = download(&format!("https://github.com/tauri-apps/binary-releases/releases/download/linuxdeploy/linuxdeploy-{linuxdeploy_arch}.AppImage"))?;

View File

@ -119,8 +119,9 @@ pub fn generate_data(
for bin in settings.binaries() { for bin in settings.binaries() {
let bin_path = settings.binary_path(bin); let bin_path = settings.binary_path(bin);
fs_utils::copy_file(&bin_path, &bin_dir.join(bin.name())) let trgt = bin_dir.join(bin.name());
.with_context(|| format!("Failed to copy binary from {bin_path:?}"))?; fs_utils::copy_file(&bin_path, &trgt)
.with_context(|| format!("Failed to copy binary from {bin_path:?} to {trgt:?}"))?;
} }
copy_resource_files(settings, &data_dir).with_context(|| "Failed to copy resource files")?; copy_resource_files(settings, &data_dir).with_context(|| "Failed to copy resource files")?;

View File

@ -65,16 +65,12 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display()); log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display());
if app_bundle_path.exists() { if app_bundle_path.exists() {
fs::remove_dir_all(&app_bundle_path).fs_context( fs::remove_dir_all(&app_bundle_path)
"failed to remove old app bundle", .fs_context("failed to remove old app bundle", &app_bundle_path)?;
app_bundle_path.to_path_buf(),
)?;
} }
let bundle_directory = app_bundle_path.join("Contents"); let bundle_directory = app_bundle_path.join("Contents");
fs::create_dir_all(&bundle_directory).fs_context( fs::create_dir_all(&bundle_directory)
"failed to create bundle directory", .fs_context("failed to create bundle directory", &bundle_directory)?;
bundle_directory.to_path_buf(),
)?;
let resources_dir = bundle_directory.join("Resources"); let resources_dir = bundle_directory.join("Resources");
let bin_dir = bundle_directory.join("MacOS"); let bin_dir = bundle_directory.join("MacOS");
@ -372,20 +368,12 @@ fn copy_frameworks_to_bundle(
) -> crate::Result<Vec<SignTarget>> { ) -> crate::Result<Vec<SignTarget>> {
let mut paths = Vec::new(); let mut paths = Vec::new();
let frameworks = settings let frameworks = settings.macos().frameworks.clone().unwrap_or_default();
.macos()
.frameworks
.as_ref()
.cloned()
.unwrap_or_default();
if frameworks.is_empty() { if frameworks.is_empty() {
return Ok(paths); return Ok(paths);
} }
let dest_dir = bundle_directory.join("Frameworks"); let dest_dir = bundle_directory.join("Frameworks");
fs::create_dir_all(&dest_dir).fs_context( fs::create_dir_all(&dest_dir).fs_context("failed to create Frameworks directory", &dest_dir)?;
"failed to create Frameworks directory",
dest_dir.to_path_buf(),
)?;
for framework in frameworks.iter() { for framework in frameworks.iter() {
if framework.ends_with(".framework") { if framework.ends_with(".framework") {
let src_path = PathBuf::from(framework); let src_path = PathBuf::from(framework);

View File

@ -44,15 +44,11 @@ pub fn bundle_project(settings: &Settings) -> crate::Result<Vec<PathBuf>> {
log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display()); log::info!(action = "Bundling"; "{} ({})", app_product_name, app_bundle_path.display());
if app_bundle_path.exists() { if app_bundle_path.exists() {
fs::remove_dir_all(&app_bundle_path).fs_context( fs::remove_dir_all(&app_bundle_path)
"failed to remove old app bundle", .fs_context("failed to remove old app bundle", &app_bundle_path)?;
app_bundle_path.to_path_buf(),
)?;
} }
fs::create_dir_all(&app_bundle_path).fs_context( fs::create_dir_all(&app_bundle_path)
"failed to create bundle directory", .fs_context("failed to create bundle directory", &app_bundle_path)?;
app_bundle_path.to_path_buf(),
)?;
for src in settings.resource_files() { for src in settings.resource_files() {
let src = src?; let src = src?;

View File

@ -753,26 +753,28 @@ pub fn build_wix_app_installer(
} }
let main_wxs_path = output_path.join("main.wxs"); 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 current_dir = std::env::current_dir()?;
let extension_regex = Regex::new("\"http://schemas.microsoft.com/wix/(\\w+)\"")?; let extension_regex = Regex::new("\"http://schemas.microsoft.com/wix/(\\w+)\"")?;
for fragment_path in fragment_paths { let input_paths =
let fragment_path = current_dir.join(fragment_path); std::iter::once(main_wxs_path).chain(fragment_paths.iter().map(|p| current_dir.join(p)));
let fragment_content = fs::read_to_string(&fragment_path)?;
let fragment_handlebars = Handlebars::new(); for input_path in input_paths {
let fragment = fragment_handlebars.render_template(&fragment_content, &data)?; 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(); 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])); let path = wix_toolset_path.join(format!("Wix{}.dll", &cap[1]));
if settings.windows().can_sign() { if settings.windows().can_sign() {
try_sign(&path, settings)?; try_sign(&path, settings)?;
} }
extensions.push(path); extensions.push(path);
} }
candle_inputs.push((fragment_path, extensions)); candle_inputs.push((input_path, extensions));
} }
let mut fragment_extensions = HashSet::new(); let mut fragment_extensions = HashSet::new();

View File

@ -298,8 +298,12 @@ fn build_nsis_app_installer(
data.insert("copyright", to_json(settings.copyright_string())); data.insert("copyright", to_json(settings.copyright_string()));
if settings.windows().can_sign() { if settings.windows().can_sign() {
let sign_cmd = format!("{:?}", sign_command("%1", &settings.sign_params())?); if settings.no_sign() {
data.insert("uninstaller_sign_cmd", to_json(sign_cmd)); 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(); let version = settings.version_string();
@ -617,13 +621,16 @@ fn build_nsis_app_installer(
fs::create_dir_all(nsis_installer_path.parent().unwrap())?; fs::create_dir_all(nsis_installer_path.parent().unwrap())?;
if settings.windows().can_sign() { if settings.windows().can_sign() {
log::info!("Signing NSIS plugins"); if let Some(plugin_copy_path) = &maybe_plugin_copy_path {
for dll in NSIS_PLUGIN_FILES { let plugin_copy_path = plugin_copy_path.join("x86-unicode");
let path = additional_plugins_path.join(dll); log::info!("Signing NSIS plugins");
if path.exists() { for dll in NSIS_PLUGIN_FILES {
try_sign(&path, settings)?; let path = plugin_copy_path.join(dll);
} else { if path.exists() {
log::warn!("Could not find {}, skipping signing", path.display()); try_sign(&path, settings)?;
} else {
log::warn!("Could not find {}, skipping signing", path.display());
}
} }
} }
} }

View File

@ -266,8 +266,7 @@ pub fn try_sign<P: AsRef<Path>>(file_path: P, settings: &Settings) -> crate::Res
pub fn should_sign(file_path: &Path) -> crate::Result<bool> { pub fn should_sign(file_path: &Path) -> crate::Result<bool> {
let is_binary = file_path let is_binary = file_path
.extension() .extension()
.and_then(|extension| extension.to_str()) .is_some_and(|ext| ext == "exe" || ext == "dll");
.is_some_and(|extension| matches!(extension, "exe" | "dll"));
if !is_binary { if !is_binary {
return Ok(false); return Ok(false);
} }

View File

@ -1,5 +1,35 @@
# Changelog # 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] ## \[2.9.4]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-cli" name = "tauri-cli"
version = "2.9.4" version = "2.9.6"
authors = ["Tauri Programme within The Commons Conservancy"] authors = ["Tauri Programme within The Commons Conservancy"]
edition = "2021" edition = "2021"
rust-version = "1.77.2" rust-version = "1.77.2"
@ -47,7 +47,7 @@ sublime_fuzzy = "0.7"
clap_complete = "4" clap_complete = "4"
clap = { version = "4", features = ["derive", "env"] } clap = { version = "4", features = ["derive", "env"] }
thiserror = "2" thiserror = "2"
tauri-bundler = { version = "2.7.3", default-features = false, path = "../tauri-bundler" } tauri-bundler = { version = "2.7.5", default-features = false, path = "../tauri-bundler" }
colored = "2" colored = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = { version = "1", features = ["preserve_order"] } serde_json = { version = "1", features = ["preserve_order"] }
@ -56,9 +56,9 @@ notify = "8"
notify-debouncer-full = "0.6" notify-debouncer-full = "0.6"
shared_child = "1" shared_child = "1"
duct = "1.0" duct = "1.0"
toml_edit = { version = "0.23", features = ["serde"] } toml_edit = { version = "0.24", features = ["serde"] }
json-patch = "3" json-patch = "3"
tauri-utils = { version = "2.8.0", path = "../tauri-utils", features = [ tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [
"isolation", "isolation",
"schema", "schema",
"config-json5", "config-json5",
@ -133,7 +133,7 @@ libc = "0.2"
[target."cfg(target_os = \"macos\")".dependencies] [target."cfg(target_os = \"macos\")".dependencies]
plist = "1" plist = "1"
tauri-macos-sign = { version = "2.3.0", path = "../tauri-macos-sign" } tauri-macos-sign = { version = "2.3.2", path = "../tauri-macos-sign" }
object = { version = "0.36", default-features = false, features = [ object = { version = "0.36", default-features = false, features = [
"macho", "macho",
"read_core", "read_core",

View File

@ -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. - 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`. - `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_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\_<api_key>.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\_<api_key>.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_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_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. - `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.

View File

@ -1,6 +1,6 @@
{ {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://schema.tauri.app/config/2.9.3", "$id": "https://schema.tauri.app/config/2.9.5",
"title": "Config", "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 ```", "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", "type": "object",
@ -231,7 +231,7 @@
"type": "string" "type": "string"
}, },
"create": { "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, "default": true,
"type": "boolean" "type": "boolean"
}, },
@ -262,7 +262,7 @@
"type": "boolean" "type": "boolean"
}, },
"x": { "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": [ "type": [
"number", "number",
"null" "null"
@ -270,7 +270,7 @@
"format": "double" "format": "double"
}, },
"y": { "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": [ "type": [
"number", "number",
"null" "null"
@ -278,19 +278,19 @@
"format": "double" "format": "double"
}, },
"width": { "width": {
"description": "The window width.", "description": "The window width in logical pixels.",
"default": 800.0, "default": 800.0,
"type": "number", "type": "number",
"format": "double" "format": "double"
}, },
"height": { "height": {
"description": "The window height.", "description": "The window height in logical pixels.",
"default": 600.0, "default": 600.0,
"type": "number", "type": "number",
"format": "double" "format": "double"
}, },
"minWidth": { "minWidth": {
"description": "The min window width.", "description": "The min window width in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -298,7 +298,7 @@
"format": "double" "format": "double"
}, },
"minHeight": { "minHeight": {
"description": "The min window height.", "description": "The min window height in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -306,7 +306,7 @@
"format": "double" "format": "double"
}, },
"maxWidth": { "maxWidth": {
"description": "The max window width.", "description": "The max window width in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -314,7 +314,7 @@
"format": "double" "format": "double"
}, },
"maxHeight": { "maxHeight": {
"description": "The max window height.", "description": "The max window height in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -673,13 +673,13 @@
], ],
"properties": { "properties": {
"width": { "width": {
"description": "Horizontal margin in physical unit", "description": "Horizontal margin in physical pixels",
"type": "integer", "type": "integer",
"format": "uint32", "format": "uint32",
"minimum": 0.0 "minimum": 0.0
}, },
"height": { "height": {
"description": "Vertical margin in physical unit", "description": "Vertical margin in physical pixels",
"type": "integer", "type": "integer",
"format": "uint32", "format": "uint32",
"minimum": 0.0 "minimum": 0.0
@ -1317,7 +1317,7 @@
"additionalProperties": false "additionalProperties": false
}, },
"FsScope": { "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": [ "anyOf": [
{ {
"description": "A list of paths that are allowed by this scope.", "description": "A list of paths that are allowed by this scope.",
@ -2012,7 +2012,7 @@
"description": "Defines the URL or assets to embed in the application.", "description": "Defines the URL or assets to embed in the application.",
"anyOf": [ "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", "type": "string",
"format": "uri" "format": "uri"
}, },
@ -2021,7 +2021,7 @@
"type": "string" "type": "string"
}, },
{ {
"description": "An array of files to embed on the app.", "description": "An array of files to embed in the app.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
@ -2849,7 +2849,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"version": { "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 <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> 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 <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.",
"type": [ "type": [
"string", "string",
"null" "null"
@ -3153,7 +3153,7 @@
"description": "Custom Signing Command configuration.", "description": "Custom Signing Command configuration.",
"anyOf": [ "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" "type": "string"
}, },
{ {

View File

@ -1,9 +1,9 @@
{ {
"cli.js": { "cli.js": {
"version": "2.9.4", "version": "2.9.6",
"node": ">= 10.0.0" "node": ">= 10.0.0"
}, },
"tauri": "2.9.3", "tauri": "2.9.5",
"tauri-build": "2.5.2", "tauri-build": "2.5.3",
"tauri-plugin": "2.5.1" "tauri-plugin": "2.5.2"
} }

View File

@ -34,7 +34,7 @@ pub fn command(options: Options) -> Result<()> {
if acl_manifests_path.exists() { if acl_manifests_path.exists() {
let plugin_manifest_json = read_to_string(&acl_manifests_path) 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::<BTreeMap<String, Manifest>>(&plugin_manifest_json) let acl = serde_json::from_str::<BTreeMap<String, Manifest>>(&plugin_manifest_json)
.context("failed to parse plugin manifest as JSON")?; .context("failed to parse plugin manifest as JSON")?;

View File

@ -8,7 +8,7 @@ use crate::{
helpers::{ helpers::{
self, self,
app_paths::{frontend_dir, tauri_dir}, app_paths::{frontend_dir, tauri_dir},
config::{get as get_config, ConfigHandle, FrontendDist}, config::{get as get_config, ConfigMetadata, FrontendDist},
}, },
info::plugins::check_mismatched_packages, info::plugins::check_mismatched_packages,
interface::{rust::get_cargo_target_dir, AppInterface, Interface}, interface::{rust::get_cargo_target_dir, AppInterface, Interface},
@ -106,11 +106,11 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
options.target.clone(), options.target.clone(),
)?; )?;
setup(&interface, &mut options, config.clone(), false)?;
let config_guard = config.lock().unwrap(); let config_guard = config.lock().unwrap();
let config_ = config_guard.as_ref().unwrap(); let config_ = config_guard.as_ref().unwrap();
setup(&interface, &mut options, config_, false)?;
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); std::env::set_var("MACOSX_DEPLOYMENT_TARGET", minimum_system_version);
} }
@ -132,7 +132,7 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
verbosity, verbosity,
ci, ci,
&interface, &interface,
&app_settings, &*app_settings,
config_, config_,
&out_dir, &out_dir,
)?; )?;
@ -144,7 +144,7 @@ pub fn command(mut options: Options, verbosity: u8) -> Result<()> {
pub fn setup( pub fn setup(
interface: &AppInterface, interface: &AppInterface,
options: &mut Options, options: &mut Options,
config: ConfigHandle, config: &ConfigMetadata,
mobile: bool, mobile: bool,
) -> Result<()> { ) -> Result<()> {
let tauri_path = tauri_dir(); let tauri_path = tauri_dir();
@ -162,44 +162,39 @@ pub fn setup(
set_current_dir(tauri_path).context("failed to set current directory")?; set_current_dir(tauri_path).context("failed to set current directory")?;
let config_guard = config.lock().unwrap(); let bundle_identifier_source = config
let config_ = config_guard.as_ref().unwrap();
let bundle_identifier_source = config_
.find_bundle_identifier_overwriter() .find_bundle_identifier_overwriter()
.unwrap_or_else(|| "tauri.conf.json".into()); .unwrap_or_else(|| "tauri.conf.json".into());
if config_.identifier == "com.tauri.dev" { if config.identifier == "com.tauri.dev" {
crate::error::bail!( 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.", "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 .identifier
.chars() .chars()
.any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.')) .any(|ch| !(ch.is_alphanumeric() || ch == '-' || ch == '.'))
{ {
crate::error::bail!( 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 (.).", "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, config.identifier,
bundle_identifier_source
); );
} }
if config_.identifier.ends_with(".app") { if config.identifier.ends_with(".app") {
log::warn!( 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.", "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, config.identifier,
bundle_identifier_source
); );
} }
if let Some(before_build) = config_.build.before_build_command.clone() { if let Some(before_build) = config.build.before_build_command.clone() {
helpers::run_hook("beforeBuildCommand", before_build, interface, options.debug)?; helpers::run_hook("beforeBuildCommand", before_build, interface, options.debug)?;
} }
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() { if !web_asset_path.exists() {
let absolute_path = web_asset_path let absolute_path = web_asset_path
.parent() .parent()
@ -252,13 +247,13 @@ pub fn setup(
} }
if options.runner.is_none() { if options.runner.is_none() {
options.runner = config_.build.runner.clone(); options.runner = config.build.runner.clone();
} }
options options
.features .features
.get_or_insert(Vec::new()) .get_or_insert(Vec::new())
.extend(config_.build.features.clone().unwrap_or_default()); .extend(config.build.features.clone().unwrap_or_default());
interface.build_options(&mut options.args, &mut options.features, mobile); interface.build_options(&mut options.args, &mut options.features, mobile);
Ok(()) Ok(())

View File

@ -158,7 +158,7 @@ pub fn command(options: Options, verbosity: u8) -> crate::Result<()> {
verbosity, verbosity,
ci, ci,
&interface, &interface,
&app_settings, &*app_settings,
config_, config_,
&out_dir, &out_dir,
) )
@ -170,7 +170,7 @@ pub fn bundle<A: AppSettings>(
verbosity: u8, verbosity: u8,
ci: bool, ci: bool,
interface: &AppInterface, interface: &AppInterface,
app_settings: &std::sync::Arc<A>, app_settings: &A,
config: &ConfigMetadata, config: &ConfigMetadata,
out_dir: &Path, out_dir: &Path,
) -> crate::Result<()> { ) -> crate::Result<()> {
@ -249,6 +249,11 @@ fn sign_updaters(
return Ok(()); return Ok(());
} }
if settings.no_sign() {
log::warn!("Updater signing is skipped due to --no-sign flag.");
return Ok(());
}
// get the public key // get the public key
let pubkey = &update_settings.pubkey; let pubkey = &update_settings.pubkey;
// check if pubkey points to a file... // check if pubkey points to a file...

View File

@ -34,7 +34,7 @@ use std::{
mod builtin_dev_server; mod builtin_dev_server;
static BEFORE_DEV: OnceLock<Mutex<Arc<SharedChild>>> = OnceLock::new(); static BEFORE_DEV: OnceLock<Mutex<Arc<SharedChild>>> = OnceLock::new();
static KILL_BEFORE_DEV_FLAG: OnceLock<AtomicBool> = OnceLock::new(); static KILL_BEFORE_DEV_FLAG: AtomicBool = AtomicBool::new(false);
#[cfg(unix)] #[cfg(unix)]
const KILL_CHILDREN_SCRIPT: &[u8] = include_bytes!("../scripts/kill-children.sh"); const KILL_CHILDREN_SCRIPT: &[u8] = include_bytes!("../scripts/kill-children.sh");
@ -218,14 +218,13 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
let status = child_ let status = child_
.wait() .wait()
.expect("failed to wait on \"beforeDevCommand\""); .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."); log::error!("The \"beforeDevCommand\" terminated with a non-zero status code.");
exit(status.code().unwrap_or(1)); exit(status.code().unwrap_or(1));
} }
}); });
BEFORE_DEV.set(Mutex::new(child)).unwrap(); BEFORE_DEV.set(Mutex::new(child)).unwrap();
KILL_BEFORE_DEV_FLAG.set(AtomicBool::default()).unwrap();
let _ = ctrlc::set_handler(move || { let _ = ctrlc::set_handler(move || {
kill_before_dev_process(); kill_before_dev_process();
@ -304,12 +303,10 @@ pub fn setup(interface: &AppInterface, options: &mut Options, config: ConfigHand
if !options.no_dev_server_wait { if !options.no_dev_server_wait {
if let Some(url) = dev_url { if let Some(url) = dev_url {
let host = url let host = url.host().expect("No host name in the URL");
.host()
.unwrap_or_else(|| panic!("No host name in the URL"));
let port = url let port = url
.port_or_known_default() .port_or_known_default()
.unwrap_or_else(|| panic!("No port number in the URL")); .expect("No port number in the URL");
let addrs; let addrs;
let addr; let addr;
let addrs = match host { let addrs = match host {
@ -380,11 +377,10 @@ pub fn on_app_exit(code: Option<i32>, reason: ExitReason, exit_on_panic: bool, n
pub fn kill_before_dev_process() { pub fn kill_before_dev_process() {
if let Some(child) = BEFORE_DEV.get() { if let Some(child) = BEFORE_DEV.get() {
let child = child.lock().unwrap(); 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; return;
} }
kill_before_dev_flag.store(true, Ordering::Relaxed); KILL_BEFORE_DEV_FLAG.store(true, Ordering::Relaxed);
#[cfg(windows)] #[cfg(windows)]
{ {
let powershell_path = std::env::var("SYSTEMROOT").map_or_else( let powershell_path = std::env::var("SYSTEMROOT").map_or_else(

View File

@ -155,9 +155,9 @@ fn inject_address(html_bytes: Vec<u8>, address: &SocketAddr) -> Vec<u8> {
} }
fn fs_read_scoped(path: PathBuf, scope: &Path) -> crate::Result<Vec<u8>> { fn fs_read_scoped(path: PathBuf, scope: &Path) -> crate::Result<Vec<u8>> {
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) { 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 { } else {
crate::error::bail!("forbidden path") crate::error::bail!("forbidden path")
} }

View File

@ -75,21 +75,13 @@ fn lookup<F: Fn(&PathBuf) -> bool>(dir: &Path, checker: F) -> Option<PathBuf> {
} }
fn env_tauri_app_path() -> Option<PathBuf> { fn env_tauri_app_path() -> Option<PathBuf> {
std::env::var(ENV_TAURI_APP_PATH) let p = PathBuf::from(std::env::var_os(ENV_TAURI_APP_PATH)?);
.map(PathBuf::from) dunce::canonicalize(p).ok()
.ok()?
.canonicalize()
.ok()
.map(|p| dunce::simplified(&p).to_path_buf())
} }
fn env_tauri_frontend_path() -> Option<PathBuf> { fn env_tauri_frontend_path() -> Option<PathBuf> {
std::env::var(ENV_TAURI_FRONTEND_PATH) let p = PathBuf::from(std::env::var_os(ENV_TAURI_FRONTEND_PATH)?);
.map(PathBuf::from) dunce::canonicalize(p).ok()
.ok()?
.canonicalize()
.ok()
.map(|p| dunce::simplified(&p).to_path_buf())
} }
pub fn resolve_tauri_dir() -> Option<PathBuf> { pub fn resolve_tauri_dir() -> Option<PathBuf> {

View File

@ -12,9 +12,9 @@ pub use tauri_utils::{config::*, platform::Target};
use std::{ use std::{
collections::HashMap, collections::HashMap,
env::{current_dir, set_current_dir, set_var}, env::{current_dir, set_current_dir, set_var},
ffi::OsStr, ffi::{OsStr, OsString},
process::exit, process::exit,
sync::{Arc, Mutex, OnceLock}, sync::Mutex,
}; };
use crate::error::Context; use crate::error::Context;
@ -30,7 +30,7 @@ pub struct ConfigMetadata {
inner: Config, inner: Config,
/// The config extensions (platform-specific config files or the config CLI argument). /// The config extensions (platform-specific config files or the config CLI argument).
/// Maps the extension name to its value. /// Maps the extension name to its value.
extensions: HashMap<String, JsonValue>, extensions: HashMap<OsString, JsonValue>,
} }
impl std::ops::Deref for ConfigMetadata { impl std::ops::Deref for ConfigMetadata {
@ -50,7 +50,7 @@ impl ConfigMetadata {
} }
/// Checks which config is overwriting the bundle identifier. /// Checks which config is overwriting the bundle identifier.
pub fn find_bundle_identifier_overwriter(&self) -> Option<String> { pub fn find_bundle_identifier_overwriter(&self) -> Option<OsString> {
for (ext, config) in &self.extensions { for (ext, config) in &self.extensions {
if let Some(identifier) = config if let Some(identifier) = config
.as_object() .as_object()
@ -66,7 +66,7 @@ impl ConfigMetadata {
} }
} }
pub type ConfigHandle = Arc<Mutex<Option<ConfigMetadata>>>; pub type ConfigHandle = &'static Mutex<Option<ConfigMetadata>>;
pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings { pub fn wix_settings(config: WixConfig) -> tauri_bundler::WixSettings {
tauri_bundler::WixSettings { tauri_bundler::WixSettings {
@ -141,9 +141,9 @@ pub fn custom_sign_settings(
} }
} }
fn config_handle() -> &'static ConfigHandle { fn config_handle() -> ConfigHandle {
static CONFIG_HANDLE: OnceLock<ConfigHandle> = OnceLock::new(); static CONFIG_HANDLE: Mutex<Option<ConfigMetadata>> = Mutex::new(None);
CONFIG_HANDLE.get_or_init(Default::default) &CONFIG_HANDLE
} }
/// Gets the static parsed config from `tauri.conf.json`. /// Gets the static parsed config from `tauri.conf.json`.
@ -153,14 +153,14 @@ fn get_internal(
target: Target, target: Target,
) -> crate::Result<ConfigHandle> { ) -> crate::Result<ConfigHandle> {
if !reload && config_handle().lock().unwrap().is_some() { if !reload && config_handle().lock().unwrap().is_some() {
return Ok(config_handle().clone()); return Ok(config_handle());
} }
let tauri_dir = super::app_paths::tauri_dir(); let tauri_dir = super::app_paths::tauri_dir();
let (mut config, config_path) = let (mut config, config_path) =
tauri_utils::config::parse::parse_value(target, tauri_dir.join("tauri.conf.json")) tauri_utils::config::parse::parse_value(target, tauri_dir.join("tauri.conf.json"))
.context("failed to parse config")?; .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 mut extensions = HashMap::new();
let original_identifier = config let original_identifier = config
@ -174,10 +174,7 @@ fn get_internal(
.context("failed to parse platform config")? .context("failed to parse platform config")?
{ {
merge(&mut config, &platform_config); merge(&mut config, &platform_config);
extensions.insert( extensions.insert(config_path.file_name().unwrap().into(), platform_config);
config_path.file_name().unwrap().to_str().unwrap().into(),
platform_config,
);
} }
if !merge_configs.is_empty() { if !merge_configs.is_empty() {
@ -203,9 +200,9 @@ fn get_internal(
for error in errors { for error in errors {
let path = error.instance_path.into_iter().join(" > "); let path = error.instance_path.into_iter().join(" > ");
if path.is_empty() { if path.is_empty() {
log::error!("`{}` error: {}", config_file_name, error); log::error!("`{config_file_name:?}` error: {}", error);
} else { } else {
log::error!("`{}` error on `{}`: {}", config_file_name, path, error); log::error!("`{config_file_name:?}` error on `{}`: {}", path, error);
} }
} }
if !reload { if !reload {
@ -243,7 +240,7 @@ fn get_internal(
extensions, extensions,
}); });
Ok(config_handle().clone()) Ok(config_handle())
} }
pub fn get(target: Target, merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> { pub fn get(target: Target, merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigHandle> {
@ -268,7 +265,7 @@ pub fn merge_with(merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigH
let handle = config_handle(); let handle = config_handle();
if merge_configs.is_empty() { if merge_configs.is_empty() {
return Ok(handle.clone()); return Ok(handle);
} }
if let Some(config_metadata) = &mut *handle.lock().unwrap() { if let Some(config_metadata) = &mut *handle.lock().unwrap() {
@ -285,7 +282,7 @@ pub fn merge_with(merge_configs: &[&serde_json::Value]) -> crate::Result<ConfigH
merge(&mut value, &merge_config); merge(&mut value, &merge_config);
config_metadata.inner = serde_json::from_value(value).context("failed to parse config")?; config_metadata.inner = serde_json::from_value(value).context("failed to parse config")?;
Ok(handle.clone()) Ok(handle)
} else { } else {
crate::error::bail!("config not loaded"); crate::error::bail!("config not loaded");
} }

View File

@ -332,13 +332,20 @@ impl PackageManager {
version: String, 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::<Vec<ListOutput>>(&stdout)
.ok()
.and_then(|out| out.into_iter().next())
.context("failed to parse pnpm list")?
} else {
serde_json::from_str::<ListOutput>(&stdout).context("failed to parse npm list")?
};
for (package, dependency) in json.dependencies.into_iter().chain(json.dev_dependencies) { for (package, dependency) in json.dependencies.into_iter().chain(json.dev_dependencies) {
let version = dependency.version; let version = dependency.version;
if let Ok(version) = semver::Version::parse(&version) { if let Ok(version) = semver::Version::parse(&version) {
versions.insert(package, version); versions.insert(package, version);
} else { } 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) Ok(versions)
@ -390,7 +397,7 @@ fn yarn_package_versions(
if let Ok(version) = semver::Version::parse(version) { if let Ok(version) = semver::Version::parse(version) {
versions.insert(name.to_owned(), version); versions.insert(name.to_owned(), version);
} else { } 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); return Ok(versions);
@ -443,7 +450,7 @@ fn yarn_berry_package_versions(
if let Ok(version) = semver::Version::parse(&version) { if let Ok(version) = semver::Version::parse(&version) {
versions.insert(name.to_owned(), version); versions.insert(name.to_owned(), version);
} else { } else {
log::error!("Failed to parse version `{version}` for NPM package `{name}`"); log::debug!("Failed to parse version `{version}` for NPM package `{name}`");
} }
} }
} }

View File

@ -146,10 +146,8 @@ where
std::fs::write(&signature_path, encoded_signature.as_bytes()) std::fs::write(&signature_path, encoded_signature.as_bytes())
.fs_context("failed to write signature file", signature_path.clone())?; .fs_context("failed to write signature file", signature_path.clone())?;
Ok(( Ok((
fs::canonicalize(&signature_path).fs_context( fs::canonicalize(&signature_path)
"failed to canonicalize signature file", .fs_context("failed to canonicalize signature file", &signature_path)?,
signature_path.clone(),
)?,
signature_box, signature_box,
)) ))
} }

View File

@ -72,7 +72,10 @@ pub fn installed_tauri_packages(
crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), crate_name).version?; crate_version(tauri_dir, manifest.as_ref(), lock.as_ref(), crate_name).version?;
let crate_version = semver::Version::parse(&crate_version) let crate_version = semver::Version::parse(&crate_version)
.inspect_err(|_| { .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()?; .ok()?;
Some((crate_name.clone(), crate_version)) Some((crate_name.clone(), crate_version))

View File

@ -78,8 +78,8 @@ impl Options {
let package_json_path = PathBuf::from(&self.directory).join("package.json"); let package_json_path = PathBuf::from(&self.directory).join("package.json");
let init_defaults = if package_json_path.exists() { let init_defaults = if package_json_path.exists() {
let package_json_text = read_to_string(&package_json_path) let package_json_text =
.fs_context("failed to read", package_json_path.clone())?; read_to_string(&package_json_path).fs_context("failed to read", &package_json_path)?;
let package_json: crate::PackageJson = let package_json: crate::PackageJson =
serde_json::from_str(&package_json_text).context("failed to parse JSON")?; serde_json::from_str(&package_json_text).context("failed to parse JSON")?;
let (framework, _) = infer_framework(&package_json_text); let (framework, _) = infer_framework(&package_json_text);

View File

@ -335,7 +335,7 @@ fn rename_app(
"" ""
}; };
let new_path = bin_path.with_file_name(format!("{main_binary_name}{extension}")); 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) Ok(new_path)
} else { } else {
Ok(bin_path) Ok(bin_path)

View File

@ -314,7 +314,7 @@ pub fn rewrite_manifest(config: &Config) -> crate::Result<(Manifest, bool)> {
if persist && original_manifest_str != new_manifest_str { if persist && original_manifest_str != new_manifest_str {
std::fs::write(&manifest_path, 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(( Ok((
Manifest { Manifest {
inner: manifest, inner: manifest,

View File

@ -21,7 +21,7 @@ pub fn migrate(tauri_dir: &Path) -> Result<()> {
migrate_manifest(&mut manifest)?; migrate_manifest(&mut manifest)?;
std::fs::write(&manifest_path, serialize_manifest(&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(()) Ok(())
} }

View File

@ -28,10 +28,8 @@ pub fn run() -> Result<()> {
migrate_npm_dependencies(frontend_dir)?; migrate_npm_dependencies(frontend_dir)?;
std::fs::write(&manifest_path, serialize_manifest(&manifest)).fs_context( std::fs::write(&manifest_path, serialize_manifest(&manifest))
"failed to rewrite Cargo manifest", .fs_context("failed to rewrite Cargo manifest", &manifest_path)?;
manifest_path.to_path_buf(),
)?;
Ok(()) Ok(())
} }

View File

@ -184,7 +184,12 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
false, false,
)?; )?;
crate::build::setup(&interface, &mut build_options, tauri_config.clone(), true)?; {
let config_guard = tauri_config.lock().unwrap();
let config_ = config_guard.as_ref().unwrap();
crate::build::setup(&interface, &mut build_options, config_, true)?;
}
let installed_targets = let installed_targets =
crate::interface::rust::installation::installed_targets().unwrap_or_default(); crate::interface::rust::installation::installed_targets().unwrap_or_default();

View File

@ -257,7 +257,7 @@ fn run_dev(
use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?; use_network_address_for_dev_url(&tauri_config, &mut dev_options, options.force_ip_prompt)?;
} }
crate::dev::setup(&interface, &mut dev_options, tauri_config.clone())?; crate::dev::setup(&interface, &mut dev_options, tauri_config)?;
let interface_options = InterfaceOptions { let interface_options = InterfaceOptions {
debug: !dev_options.release_mode, debug: !dev_options.release_mode,

View File

@ -313,7 +313,7 @@ pub fn command(options: Options, noise_level: NoiseLevel) -> Result<BuiltApplica
tempfile::NamedTempFile::new().context("failed to create temporary file")?; tempfile::NamedTempFile::new().context("failed to create temporary file")?;
let merged_plist = merge_plist(vec![ let merged_plist = merge_plist(vec![
export_options_plist_path.clone().into(), export_options_plist_path.into(),
plist::Value::from(export_options_plist).into(), plist::Value::from(export_options_plist).into(),
])?; ])?;
merged_plist merged_plist
@ -369,7 +369,12 @@ fn run_build(
Profile::Release Profile::Release
}; };
crate::build::setup(interface, &mut build_options, tauri_config.clone(), true)?; crate::build::setup(
interface,
&mut build_options,
tauri_config.lock().unwrap().as_ref().unwrap(),
true,
)?;
let app_settings = interface.app_settings(); let app_settings = interface.app_settings();
let out_dir = app_settings.out_dir(&InterfaceOptions { let out_dir = app_settings.out_dir(&InterfaceOptions {

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
## \[2.5.2]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
## \[2.5.1] ## \[2.5.1]
### Performance Improvements ### Performance Improvements

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.5.1" version = "2.5.2"
description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`" description = "code generation meant to be consumed inside of `tauri` through `tauri-build` or `tauri-macros`"
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -20,7 +20,7 @@ quote = "1"
syn = "2" syn = "2"
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
tauri-utils = { version = "2.8.0", path = "../tauri-utils", features = [ tauri-utils = { version = "2.8.1", path = "../tauri-utils", features = [
"build", "build",
] } ] }
thiserror = "2" thiserror = "2"
@ -30,7 +30,7 @@ brotli = { version = "8", optional = true, default-features = false, features =
] } ] }
uuid = { version = "1", features = ["v4"] } uuid = { version = "1", features = ["v4"] }
semver = "1" semver = "1"
ico = "0.4" ico = "0.5"
png = "0.17" png = "0.17"
json-patch = "3" json-patch = "3"
url = "2" url = "2"

View File

@ -1,5 +1,17 @@
# Changelog # 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] ## \[2.3.0]
### Enhancements ### Enhancements

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-macos-sign" name = "tauri-macos-sign"
version = "2.3.0" version = "2.3.2"
authors = ["Tauri Programme within The Commons Conservancy"] authors = ["Tauri Programme within The Commons Conservancy"]
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
keywords = ["codesign", "signing", "macos", "ios", "tauri"] keywords = ["codesign", "signing", "macos", "ios", "tauri"]

View File

@ -238,7 +238,7 @@ fn notarize_inner(
String::from_utf8_lossy(&output.stdout) String::from_utf8_lossy(&output.stdout)
))) )))
} else { } else {
Err(Error::Notarize(log_message.to_string())) Err(Error::Notarize(log_message))
} }
} else { } else {
Err(Error::ParseNotarytoolOutput { Err(Error::ParseNotarytoolOutput {

View File

@ -1,5 +1,12 @@
# Changelog # Changelog
## \[2.5.2]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
- Upgraded to `tauri-codegen@2.5.2`
## \[2.5.1] ## \[2.5.1]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-macros" name = "tauri-macros"
version = "2.5.1" version = "2.5.2"
description = "Macros for the tauri crate." description = "Macros for the tauri crate."
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -20,8 +20,8 @@ proc-macro2 = { version = "1", features = ["span-locations"] }
quote = "1" quote = "1"
syn = { version = "2", features = ["full"] } syn = { version = "2", features = ["full"] }
heck = "0.5" heck = "0.5"
tauri-codegen = { version = "2.5.1", default-features = false, path = "../tauri-codegen" } tauri-codegen = { version = "2.5.2", default-features = false, path = "../tauri-codegen" }
tauri-utils = { version = "2.8.0", path = "../tauri-utils" } tauri-utils = { version = "2.8.1", path = "../tauri-utils" }
[features] [features]
custom-protocol = [] custom-protocol = []

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
## \[2.5.2]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
## \[2.5.1] ## \[2.5.1]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin" name = "tauri-plugin"
version = "2.5.1" version = "2.5.2"
description = "Build script and runtime Tauri plugin definitions" description = "Build script and runtime Tauri plugin definitions"
authors.workspace = true authors.workspace = true
homepage.workspace = true homepage.workspace = true
@ -28,7 +28,7 @@ runtime = []
[dependencies] [dependencies]
anyhow = { version = "1", optional = true } anyhow = { version = "1", optional = true }
serde = { version = "1", optional = true } serde = { version = "1", optional = true }
tauri-utils = { version = "2.8.0", default-features = false, features = [ tauri-utils = { version = "2.8.1", default-features = false, features = [
"build", "build",
], path = "../tauri-utils" } ], path = "../tauri-utils" }
serde_json = { version = "1", optional = true } serde_json = { version = "1", optional = true }

View File

@ -1,5 +1,18 @@
# Changelog # 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] ## \[2.9.1]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-runtime-wry" name = "tauri-runtime-wry"
version = "2.9.1" version = "2.9.3"
description = "Wry bindings to the Tauri runtime" description = "Wry bindings to the Tauri runtime"
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -20,8 +20,8 @@ wry = { version = "0.53.5", default-features = false, features = [
"linux-body", "linux-body",
] } ] }
tao = { version = "0.34.5", default-features = false, features = ["rwh_06"] } tao = { version = "0.34.5", default-features = false, features = ["rwh_06"] }
tauri-runtime = { version = "2.9.1", path = "../tauri-runtime" } tauri-runtime = { version = "2.9.2", path = "../tauri-runtime" }
tauri-utils = { version = "2.8.0", path = "../tauri-utils" } tauri-utils = { version = "2.8.1", path = "../tauri-utils" }
raw-window-handle = "0.6" raw-window-handle = "0.6"
http = "1" http = "1"
url = "2" url = "2"

View File

@ -2482,6 +2482,18 @@ impl Drop for WebviewWrapper {
if let Some(web_context) = context_store.get_mut(&self.context_key) { if let Some(web_context) = context_store.get_mut(&self.context_key) {
web_context.referenced_by_webviews.remove(&self.label); 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() { if web_context.referenced_by_webviews.is_empty() {
context_store.remove(&self.context_key); context_store.remove(&self.context_key);
} }

View File

@ -4,14 +4,15 @@
use gtk::prelude::MonitorExt; use gtk::prelude::MonitorExt;
use tao::platform::unix::MonitorHandleExtUnix; 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 { impl super::MonitorExt for tao::monitor::MonitorHandle {
fn work_area(&self) -> PhysicalRect<i32, u32> { fn work_area(&self) -> PhysicalRect<i32, u32> {
let rect = self.gdk_monitor().workarea(); let rect = self.gdk_monitor().workarea();
let scale_factor = self.scale_factor();
PhysicalRect { PhysicalRect {
size: PhysicalSize::new(rect.width() as u32, rect.height() as u32), size: LogicalSize::new(rect.width() as u32, rect.height() as u32).to_physical(scale_factor),
position: PhysicalPosition::new(rect.x(), rect.y()), position: LogicalPosition::new(rect.x(), rect.y()).to_physical(scale_factor),
} }
} }
} }

View File

@ -1,5 +1,11 @@
# Changelog # Changelog
## \[2.9.2]
### Dependencies
- Upgraded to `tauri-utils@2.8.1`
## \[2.9.1] ## \[2.9.1]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-runtime" name = "tauri-runtime"
version = "2.9.1" version = "2.9.2"
description = "Runtime for Tauri applications" description = "Runtime for Tauri applications"
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -27,7 +27,7 @@ targets = [
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde_json = "1" serde_json = "1"
thiserror = "2" thiserror = "2"
tauri-utils = { version = "2.8.0", path = "../tauri-utils" } tauri-utils = { version = "2.8.1", path = "../tauri-utils" }
http = "1" http = "1"
raw-window-handle = "0.6" raw-window-handle = "0.6"
url = { version = "2" } url = { version = "2" }

View File

@ -23,7 +23,7 @@ use std::{
sync::Arc, sync::Arc,
}; };
type UriSchemeProtocol = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>) type UriSchemeProtocolHandler = dyn Fn(&str, http::Request<Vec<u8>>, Box<dyn FnOnce(http::Response<Cow<'static, [u8]>>) + Send>)
+ Send + Send
+ Sync + Sync
+ 'static; + 'static;
@ -199,7 +199,8 @@ pub struct PendingWebview<T: UserEvent, R: Runtime<T>> {
/// The [`WebviewAttributes`] that the webview will be created with. /// The [`WebviewAttributes`] that the webview will be created with.
pub webview_attributes: WebviewAttributes, pub webview_attributes: WebviewAttributes,
pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocol>>, /// Custom protocols to register on the webview
pub uri_scheme_protocols: HashMap<String, Box<UriSchemeProtocolHandler>>,
/// How to handle IPC calls on the webview. /// How to handle IPC calls on the webview.
pub ipc_handler: Option<WebviewIpcHandler<T, R>>, pub ipc_handler: Option<WebviewIpcHandler<T, R>>,
@ -263,12 +264,12 @@ impl<T: UserEvent, R: Runtime<T>> PendingWebview<T, R> {
>( >(
&mut self, &mut self,
uri_scheme: N, uri_scheme: N,
protocol: H, protocol_handler: H,
) { ) {
let uri_scheme = uri_scheme.into(); let uri_scheme = uri_scheme.into();
self self
.uri_scheme_protocols .uri_scheme_protocols
.insert(uri_scheme, Box::new(protocol)); .insert(uri_scheme, Box::new(protocol_handler));
} }
#[cfg(target_os = "android")] #[cfg(target_os = "android")]

View File

@ -247,19 +247,19 @@ pub trait WindowBuilder: WindowBuilderBase {
#[must_use] #[must_use]
fn center(self) -> Self; fn center(self) -> Self;
/// The initial position of the window's. /// The initial position of the window in logical pixels.
#[must_use] #[must_use]
fn position(self, x: f64, y: f64) -> Self; fn position(self, x: f64, y: f64) -> Self;
/// Window size. /// Window size in logical pixels.
#[must_use] #[must_use]
fn inner_size(self, width: f64, height: f64) -> Self; fn inner_size(self, width: f64, height: f64) -> Self;
/// Window min inner size. /// Window min inner size in logical pixels.
#[must_use] #[must_use]
fn min_inner_size(self, min_width: f64, min_height: f64) -> Self; 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] #[must_use]
fn max_inner_size(self, max_width: f64, max_height: f64) -> Self; fn max_inner_size(self, max_width: f64, max_height: f64) -> Self;

View File

@ -1,6 +1,6 @@
{ {
"$schema": "http://json-schema.org/draft-07/schema#", "$schema": "http://json-schema.org/draft-07/schema#",
"$id": "https://schema.tauri.app/config/2.9.3", "$id": "https://schema.tauri.app/config/2.9.5",
"title": "Config", "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 ```", "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", "type": "object",
@ -231,7 +231,7 @@
"type": "string" "type": "string"
}, },
"create": { "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, "default": true,
"type": "boolean" "type": "boolean"
}, },
@ -262,7 +262,7 @@
"type": "boolean" "type": "boolean"
}, },
"x": { "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": [ "type": [
"number", "number",
"null" "null"
@ -270,7 +270,7 @@
"format": "double" "format": "double"
}, },
"y": { "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": [ "type": [
"number", "number",
"null" "null"
@ -278,19 +278,19 @@
"format": "double" "format": "double"
}, },
"width": { "width": {
"description": "The window width.", "description": "The window width in logical pixels.",
"default": 800.0, "default": 800.0,
"type": "number", "type": "number",
"format": "double" "format": "double"
}, },
"height": { "height": {
"description": "The window height.", "description": "The window height in logical pixels.",
"default": 600.0, "default": 600.0,
"type": "number", "type": "number",
"format": "double" "format": "double"
}, },
"minWidth": { "minWidth": {
"description": "The min window width.", "description": "The min window width in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -298,7 +298,7 @@
"format": "double" "format": "double"
}, },
"minHeight": { "minHeight": {
"description": "The min window height.", "description": "The min window height in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -306,7 +306,7 @@
"format": "double" "format": "double"
}, },
"maxWidth": { "maxWidth": {
"description": "The max window width.", "description": "The max window width in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -314,7 +314,7 @@
"format": "double" "format": "double"
}, },
"maxHeight": { "maxHeight": {
"description": "The max window height.", "description": "The max window height in logical pixels.",
"type": [ "type": [
"number", "number",
"null" "null"
@ -673,13 +673,13 @@
], ],
"properties": { "properties": {
"width": { "width": {
"description": "Horizontal margin in physical unit", "description": "Horizontal margin in physical pixels",
"type": "integer", "type": "integer",
"format": "uint32", "format": "uint32",
"minimum": 0.0 "minimum": 0.0
}, },
"height": { "height": {
"description": "Vertical margin in physical unit", "description": "Vertical margin in physical pixels",
"type": "integer", "type": "integer",
"format": "uint32", "format": "uint32",
"minimum": 0.0 "minimum": 0.0
@ -1317,7 +1317,7 @@
"additionalProperties": false "additionalProperties": false
}, },
"FsScope": { "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": [ "anyOf": [
{ {
"description": "A list of paths that are allowed by this scope.", "description": "A list of paths that are allowed by this scope.",
@ -2012,7 +2012,7 @@
"description": "Defines the URL or assets to embed in the application.", "description": "Defines the URL or assets to embed in the application.",
"anyOf": [ "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", "type": "string",
"format": "uri" "format": "uri"
}, },
@ -2021,7 +2021,7 @@
"type": "string" "type": "string"
}, },
{ {
"description": "An array of files to embed on the app.", "description": "An array of files to embed in the app.",
"type": "array", "type": "array",
"items": { "items": {
"type": "string" "type": "string"
@ -2849,7 +2849,7 @@
"type": "object", "type": "object",
"properties": { "properties": {
"version": { "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 <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> 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 <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.",
"type": [ "type": [
"string", "string",
"null" "null"
@ -3153,7 +3153,7 @@
"description": "Custom Signing Command configuration.", "description": "Custom Signing Command configuration.",
"anyOf": [ "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" "type": "string"
}, },
{ {

View File

@ -8,8 +8,8 @@ publish = false
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
worker = { version = "0.6", features = ['http', 'axum'] } worker = { version = "0.7", features = ['http', 'axum'] }
worker-macros = { version = "0.6", features = ['http'] } worker-macros = { version = "0.7", features = ['http'] }
console_error_panic_hook = { version = "0.1" } console_error_panic_hook = { version = "0.1" }
axum = { version = "0.8", default-features = false } axum = { version = "0.8", default-features = false }
tower-service = "0.3" tower-service = "0.3"

View File

@ -7,8 +7,9 @@ main = "build/worker/shim.mjs"
compatibility_date = "2023-08-23" compatibility_date = "2023-08-23"
send_metrics = false send_metrics = false
# The minor version of worker-build must match worker/worker-macros in Cargo.toml!
[build] [build]
command = "cargo install -q worker-build && worker-build --release" command = "cargo install -q worker-build@^0.7 && worker-build --release"
[observability] [observability]
enabled = true enabled = true

View File

@ -1,5 +1,11 @@
# Changelog # 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] ## \[2.8.0]
### New Features ### New Features

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-utils" name = "tauri-utils"
version = "2.8.0" version = "2.8.1"
description = "Utilities for Tauri" description = "Utilities for Tauri"
exclude = ["CHANGELOG.md", "/target"] exclude = ["CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"

View File

@ -317,6 +317,9 @@ pub fn generate_capability_schema(
extend_permission_entry_schema(&mut schema, acl); extend_permission_entry_schema(&mut schema, acl);
let schema_str = serde_json::to_string_pretty(&schema).unwrap(); let schema_str = serde_json::to_string_pretty(&schema).unwrap();
// 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 = PathBuf::from(CAPABILITIES_SCHEMA_FOLDER_PATH); let out_dir = PathBuf::from(CAPABILITIES_SCHEMA_FOLDER_PATH);
fs::create_dir_all(&out_dir)?; fs::create_dir_all(&out_dir)?;
@ -389,6 +392,9 @@ pub fn generate_permissions_schema<P: AsRef<Path>>(
let schema_str = serde_json::to_string_pretty(&schema)?; 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); 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()))?; fs::create_dir_all(&out_dir).map_err(|e| Error::CreateDir(e, out_dir.clone()))?;

View File

@ -739,7 +739,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. /// 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 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 <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info. /// See <https://learn.microsoft.com/en-us/windows/win32/msi/productversion> for more info.
pub version: Option<String>, pub version: Option<String>,
@ -996,7 +996,7 @@ pub enum CustomSignCommandConfig {
/// This is a simpler notation for the command. /// 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. /// 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), Command(String),
/// An object notation of the command. /// An object notation of the command.
/// ///
@ -1839,9 +1839,9 @@ pub struct WindowEffectsConfig {
#[cfg_attr(feature = "schema", derive(JsonSchema))] #[cfg_attr(feature = "schema", derive(JsonSchema))]
#[serde(rename_all = "camelCase", deny_unknown_fields)] #[serde(rename_all = "camelCase", deny_unknown_fields)]
pub struct PreventOverflowMargin { pub struct PreventOverflowMargin {
/// Horizontal margin in physical unit /// Horizontal margin in physical pixels
pub width: u32, pub width: u32,
/// Vertical margin in physical unit /// Vertical margin in physical pixels
pub height: u32, pub height: u32,
} }
@ -1899,7 +1899,7 @@ pub struct WindowConfig {
/// ```rust /// ```rust
/// tauri::Builder::default() /// tauri::Builder::default()
/// .setup(|app| { /// .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(()) /// Ok(())
/// }); /// });
/// ``` /// ```
@ -1919,26 +1919,26 @@ pub struct WindowConfig {
/// Whether or not the window starts centered or not. /// Whether or not the window starts centered or not.
#[serde(default)] #[serde(default)]
pub center: bool, 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<f64>, pub x: Option<f64>,
/// 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<f64>, pub y: Option<f64>,
/// The window width. /// The window width in logical pixels.
#[serde(default = "default_width")] #[serde(default = "default_width")]
pub width: f64, pub width: f64,
/// The window height. /// The window height in logical pixels.
#[serde(default = "default_height")] #[serde(default = "default_height")]
pub height: f64, pub height: f64,
/// The min window width. /// The min window width in logical pixels.
#[serde(alias = "min-width")] #[serde(alias = "min-width")]
pub min_width: Option<f64>, pub min_width: Option<f64>,
/// The min window height. /// The min window height in logical pixels.
#[serde(alias = "min-height")] #[serde(alias = "min-height")]
pub min_height: Option<f64>, pub min_height: Option<f64>,
/// The max window width. /// The max window width in logical pixels.
#[serde(alias = "max-width")] #[serde(alias = "max-width")]
pub max_width: Option<f64>, pub max_width: Option<f64>,
/// The max window height. /// The max window height in logical pixels.
#[serde(alias = "max-height")] #[serde(alias = "max-height")]
pub max_height: Option<f64>, pub max_height: Option<f64>,
/// Whether or not to prevent the window from overflowing the workarea /// Whether or not to prevent the window from overflowing the workarea
@ -2267,7 +2267,7 @@ impl Default for WindowConfig {
closable: true, closable: true,
title: default_title(), title: default_title(),
fullscreen: false, fullscreen: false,
focus: false, focus: true,
focusable: true, focusable: true,
transparent: false, transparent: false,
maximized: false, maximized: false,
@ -2475,8 +2475,8 @@ impl Default for DisabledCspModificationKind {
/// Each pattern can start with a variable that resolves to a system base directory. /// Each pattern can start with a variable that resolves to a system base directory.
/// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`, /// The variables are: `$AUDIO`, `$CACHE`, `$CONFIG`, `$DATA`, `$LOCALDATA`, `$DESKTOP`,
/// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`, /// `$DOCUMENT`, `$DOWNLOAD`, `$EXE`, `$FONT`, `$HOME`, `$PICTURE`, `$PUBLIC`, `$RUNTIME`,
/// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$APP`, `$LOG`, `$TEMP`, `$APPCONFIG`, `$APPDATA`, /// `$TEMPLATE`, `$VIDEO`, `$RESOURCE`, `$TEMP`,
/// `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`. /// `$APPCONFIG`, `$APPDATA`, `$APPLOCALDATA`, `$APPCACHE`, `$APPLOG`.
#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)] #[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
#[serde(untagged)] #[serde(untagged)]
#[cfg_attr(feature = "schema", derive(JsonSchema))] #[cfg_attr(feature = "schema", derive(JsonSchema))]
@ -3205,11 +3205,11 @@ fn default_min_sdk_version() -> u32 {
#[serde(untagged, deny_unknown_fields)] #[serde(untagged, deny_unknown_fields)]
#[non_exhaustive] #[non_exhaustive]
pub enum FrontendDist { 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), Url(Url),
/// Path to a directory containing the frontend dist assets. /// Path to a directory containing the frontend dist assets.
Directory(PathBuf), Directory(PathBuf),
/// An array of files to embed on the app. /// An array of files to embed in the app.
Files(Vec<PathBuf>), Files(Vec<PathBuf>),
} }
@ -4654,4 +4654,12 @@ mod test {
assert!(object_json.contains("\"cwd\":null") || !object_json.contains("cwd")); assert!(object_json.contains("\"cwd\":null") || !object_json.contains("cwd"));
assert!(object_json.contains("\"args\":null") || !object_json.contains("args")); 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);
}
} }

View File

@ -209,7 +209,7 @@ pub fn read_platform(
/// JSON with `.json`. /// JSON with `.json`.
pub fn does_supported_file_name_exist(target: Target, path: impl Into<PathBuf>) -> bool { pub fn does_supported_file_name_exist(target: Target, path: impl Into<PathBuf>) -> bool {
let path = path.into(); 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 let lookup_platform_config = ENABLED_FORMATS
.iter() .iter()
.any(|format| source_file_name == format.into_platform_file_name(target)); .any(|format| source_file_name == format.into_platform_file_name(target));

View File

@ -238,16 +238,12 @@ const CARGO_OUTPUT_DIRECTORIES: &[&str] = &["debug", "release", "custom-profile"
#[cfg(test)] #[cfg(test)]
fn is_cargo_output_directory(path: &std::path::Path) -> bool { fn is_cargo_output_directory(path: &std::path::Path) -> bool {
let last_component = path let Some(last_component) = path.components().next_back() else {
.components() return false;
.next_back() };
.unwrap()
.as_os_str()
.to_str()
.unwrap();
CARGO_OUTPUT_DIRECTORIES CARGO_OUTPUT_DIRECTORIES
.iter() .iter()
.any(|dirname| &last_component == dirname) .any(|dirname| &last_component.as_os_str() == dirname)
} }
/// Computes the resource directory of the current environment. /// Computes the resource directory of the current environment.

View File

@ -97,9 +97,7 @@ impl<'a> ResourcePaths<'a> {
iter: ResourcePathsIter { iter: ResourcePathsIter {
pattern_iter: PatternIter::Slice(patterns.iter()), pattern_iter: PatternIter::Slice(patterns.iter()),
allow_walk, allow_walk,
current_path: None,
current_pattern: None, current_pattern: None,
current_dest: None,
walk_iter: None, walk_iter: None,
glob_iter: None, glob_iter: None,
}, },
@ -112,9 +110,7 @@ impl<'a> ResourcePaths<'a> {
iter: ResourcePathsIter { iter: ResourcePathsIter {
pattern_iter: PatternIter::Map(patterns.iter()), pattern_iter: PatternIter::Map(patterns.iter()),
allow_walk, allow_walk,
current_path: None,
current_pattern: None, current_pattern: None,
current_dest: None,
walk_iter: None, walk_iter: None,
glob_iter: None, glob_iter: None,
}, },
@ -136,13 +132,9 @@ pub struct ResourcePathsIter<'a> {
/// whether the resource paths allows directories or not. /// whether the resource paths allows directories or not.
allow_walk: bool, allow_walk: bool,
current_path: Option<PathBuf>, /// The (key, value) of map when `pattern_iter` is a [`PatternIter::Map`],
/// The key of map when `pattern_iter` is a [`PatternIter::Map`],
/// used for determining [`Resource::target`] /// used for determining [`Resource::target`]
current_pattern: Option<String>, current_pattern: Option<(String, PathBuf)>,
/// The value of the map when `pattern_iter` is a [`PatternIter::Map`],
/// used for determining [`Resource::target`]
current_dest: Option<PathBuf>,
walk_iter: Option<walkdir::IntoIter>, walk_iter: Option<walkdir::IntoIter>,
glob_iter: Option<glob::Paths>, glob_iter: Option<glob::Paths>,
@ -157,8 +149,7 @@ impl ResourcePathsIter<'_> {
Err(err) => return Some(Err(err.into())), Err(err) => return Some(Err(err.into())),
}; };
self.current_path = Some(normalize(&entry)); self.next_current_path(normalize(&entry))
self.next_current_path()
} }
fn next_walk_iter(&mut self) -> Option<crate::Result<Resource>> { fn next_walk_iter(&mut self) -> Option<crate::Result<Resource>> {
@ -169,8 +160,7 @@ impl ResourcePathsIter<'_> {
Err(err) => return Some(Err(err.into())), Err(err) => return Some(Err(err.into())),
}; };
self.current_path = Some(normalize(entry.path())); self.next_current_path(normalize(entry.path()))
self.next_current_path()
} }
fn resource_from_path(&mut self, path: &Path) -> crate::Result<Resource> { fn resource_from_path(&mut self, path: &Path) -> crate::Result<Resource> {
@ -180,12 +170,11 @@ impl ResourcePathsIter<'_> {
Ok(Resource { Ok(Resource {
path: path.to_path_buf(), 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 processing a directory, preserve directory structure under current_dest
if self.walk_iter.is_some() { if self.walk_iter.is_some() {
let current_pattern = self.current_pattern.as_ref().unwrap(); dest.join(path.strip_prefix(pattern).unwrap_or(path))
current_dest.join(path.strip_prefix(current_pattern).unwrap_or(path)) } else if dest.components().count() == 0 {
} else if current_dest.components().count() == 0 {
// if current_dest is empty while processing a file pattern or glob // if current_dest is empty while processing a file pattern or glob
// we preserve the file name as it is // we preserve the file name as it is
PathBuf::from(path.file_name().unwrap()) PathBuf::from(path.file_name().unwrap())
@ -193,9 +182,9 @@ impl ResourcePathsIter<'_> {
// if processing a glob and current_dest is not empty // if processing a glob and current_dest is not empty
// we put all globbed paths under current_dest // we put all globbed paths under current_dest
// preserving the file name as it is // preserving the file name as it is
current_dest.join(path.file_name().unwrap()) dest.join(path.file_name().unwrap())
} else { } else {
current_dest.clone() dest.clone()
} }
} else { } else {
// If `pattern_iter` is a [`PatternIter::Slice`] // If `pattern_iter` is a [`PatternIter::Slice`]
@ -204,11 +193,7 @@ impl ResourcePathsIter<'_> {
}) })
} }
fn next_current_path(&mut self) -> Option<crate::Result<Resource>> { fn next_current_path(&mut self, path: PathBuf) -> Option<crate::Result<Resource>> {
// should be safe to unwrap since every call to `self.next_current_path()`
// is preceded with assignment to `self.current_path`
let path = self.current_path.take().unwrap();
let is_dir = path.is_dir(); let is_dir = path.is_dir();
if is_dir { if is_dir {
@ -238,15 +223,12 @@ impl ResourcePathsIter<'_> {
fn next_pattern(&mut self) -> Option<crate::Result<Resource>> { fn next_pattern(&mut self) -> Option<crate::Result<Resource>> {
self.current_pattern = None; self.current_pattern = None;
self.current_dest = None;
self.current_path = None;
let pattern = match &mut self.pattern_iter { let pattern = match &mut self.pattern_iter {
PatternIter::Slice(iter) => iter.next()?, PatternIter::Slice(iter) => iter.next()?,
PatternIter::Map(iter) => { PatternIter::Map(iter) => {
let (pattern, dest) = iter.next()?; let (pattern, dest) = iter.next()?;
self.current_pattern = Some(pattern.clone()); self.current_pattern = Some((pattern.clone(), resource_relpath(Path::new(dest))));
self.current_dest = Some(resource_relpath(Path::new(dest)));
pattern pattern
} }
}; };
@ -265,8 +247,7 @@ impl ResourcePathsIter<'_> {
} }
} }
self.current_path = Some(normalize(Path::new(pattern))); self.next_current_path(normalize(Path::new(pattern)))
self.next_current_path()
} }
} }
@ -282,10 +263,6 @@ impl Iterator for ResourcePathsIter<'_> {
type Item = crate::Result<Resource>; type Item = crate::Result<Resource>;
fn next(&mut self) -> Option<crate::Result<Resource>> { fn next(&mut self) -> Option<crate::Result<Resource>> {
if self.current_path.is_some() {
return self.next_current_path();
}
if self.walk_iter.is_some() { if self.walk_iter.is_some() {
match self.next_walk_iter() { match self.next_walk_iter() {
Some(r) => return Some(r), Some(r) => return Some(r),

View File

@ -1,5 +1,30 @@
# Changelog # 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] ## \[2.9.3]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
[package] [package]
name = "tauri" name = "tauri"
version = "2.9.3" version = "2.9.5"
description = "Make tiny, secure apps for all desktop platforms with Tauri" description = "Make tiny, secure apps for all desktop platforms with Tauri"
exclude = ["/test", "/.scripts", "CHANGELOG.md", "/target"] exclude = ["/test", "/.scripts", "CHANGELOG.md", "/target"]
readme = "README.md" readme = "README.md"
@ -55,12 +55,12 @@ uuid = { version = "1", features = ["v4"], optional = true }
url = "2" url = "2"
anyhow = "1" anyhow = "1"
thiserror = "2" thiserror = "2"
tauri-runtime = { version = "2.9.1", path = "../tauri-runtime" } tauri-runtime = { version = "2.9.2", path = "../tauri-runtime" }
tauri-macros = { version = "2.5.1", path = "../tauri-macros" } tauri-macros = { version = "2.5.2", path = "../tauri-macros" }
tauri-utils = { version = "2.8.0", features = [ tauri-utils = { version = "2.8.1", features = [
"resources", "resources",
], path = "../tauri-utils" } ], path = "../tauri-utils" }
tauri-runtime-wry = { version = "2.9.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" getrandom = "0.3"
serde_repr = "0.1" serde_repr = "0.1"
http = "1" http = "1"
@ -162,8 +162,8 @@ objc2-ui-kit = { version = "0.3.0", default-features = false, features = [
[build-dependencies] [build-dependencies]
glob = "0.3" glob = "0.3"
heck = "0.5" heck = "0.5"
tauri-build = { path = "../tauri-build/", default-features = false, version = "2.5.2" } tauri-build = { path = "../tauri-build/", default-features = false, version = "2.5.3" }
tauri-utils = { path = "../tauri-utils/", version = "2.8.0", features = [ tauri-utils = { path = "../tauri-utils/", version = "2.8.1", features = [
"build", "build",
] } ] }

View File

@ -295,12 +295,11 @@ impl<R: Runtime> AssetResolver<R> {
/// were configured with [`crate::webview::WebviewBuilder::use_https_scheme`] or `tauri.conf.json > app > windows > useHttpsScheme`. /// 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`]. /// 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 production, this resolves to the embedded asset bundled in the app executable
/// in dev when [`devUrl`](https://v2.tauri.app/reference/config/#devurl) points to a folder in your filesystem /// which contains your frontend assets in [`frontendDist`](https://v2.tauri.app/reference/config/#frontenddist) during build time.
/// or in production when [`frontendDist`](https://v2.tauri.app/reference/config/#frontenddist)
/// points to your frontend assets.
/// ///
/// 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. /// Note that the dist directory must exist so you might need to build your frontend assets first.
pub fn get(&self, path: String) -> Option<Asset> { pub fn get(&self, path: String) -> Option<Asset> {
let use_https_scheme = self let use_https_scheme = self
@ -318,9 +317,8 @@ impl<R: Runtime> AssetResolver<R> {
pub fn get_for_scheme(&self, path: String, use_https_scheme: bool) -> Option<Asset> { pub fn get_for_scheme(&self, path: String, use_https_scheme: bool) -> Option<Asset> {
#[cfg(dev)] #[cfg(dev)]
{ {
// on dev if the devPath is a path to a directory we have the embedded assets // We don't bundle the assets when in dev mode and `devUrl` is set, so fall back to read from `frontendDist` directly
// so we can use get_asset() directly // TODO: Maybe handle `FrontendDist::Files` as well
// we only fallback to reading from distDir directly if we're using an external URL (which is likely)
if let (Some(_), Some(crate::utils::config::FrontendDist::Directory(dist_path))) = ( if let (Some(_), Some(crate::utils::config::FrontendDist::Directory(dist_path))) = (
&self.manager.config().build.dev_url, &self.manager.config().build.dev_url,
&self.manager.config().build.frontend_dist, &self.manager.config().build.frontend_dist,
@ -2083,13 +2081,13 @@ tauri::Builder::default()
>( >(
mut self, mut self,
uri_scheme: N, uri_scheme: N,
protocol: H, protocol_handler: H,
) -> Self { ) -> Self {
self.uri_scheme_protocols.insert( self.uri_scheme_protocols.insert(
uri_scheme.into(), uri_scheme.into(),
Arc::new(UriSchemeProtocol { Arc::new(UriSchemeProtocol {
protocol: Box::new(move |ctx, request, responder| { handler: Box::new(move |ctx, request, responder| {
responder.respond(protocol(ctx, request)) responder.respond(protocol_handler(ctx, request))
}), }),
}), }),
); );
@ -2125,8 +2123,8 @@ tauri::Builder::default()
/// .body("failed to read file".as_bytes().to_vec()) /// .body("failed to read file".as_bytes().to_vec())
/// .unwrap() /// .unwrap()
/// ); /// );
/// } /// }
/// }); /// });
/// }); /// });
/// ``` /// ```
/// ///
@ -2147,12 +2145,12 @@ tauri::Builder::default()
>( >(
mut self, mut self,
uri_scheme: N, uri_scheme: N,
protocol: H, protocol_handler: H,
) -> Self { ) -> Self {
self.uri_scheme_protocols.insert( self.uri_scheme_protocols.insert(
uri_scheme.into(), uri_scheme.into(),
Arc::new(UriSchemeProtocol { Arc::new(UriSchemeProtocol {
protocol: Box::new(protocol), handler: Box::new(protocol_handler),
}), }),
); );
self self

View File

@ -333,25 +333,9 @@ impl<R: Runtime> AppManager<R> {
self.state.clone() self.state.clone()
} }
/// Get the base path to serve data from. /// 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`
/// * In dev mode, this will be based on the `devUrl` configuration value. pub(crate) fn tauri_protocol_url(&self, https: bool) -> Cow<'_, Url> {
/// * 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> {
if cfg!(windows) || cfg!(target_os = "android") { if cfg!(windows) || cfg!(target_os = "android") {
let scheme = if https { "https" } else { "http" }; let scheme = if https { "https" } else { "http" };
Cow::Owned(Url::parse(&format!("{scheme}://tauri.localhost")).unwrap()) Cow::Owned(Url::parse(&format!("{scheme}://tauri.localhost")).unwrap())
@ -360,13 +344,24 @@ impl<R: Runtime> AppManager<R> {
} }
} }
/// 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. /// * In dev mode, this is the [`devUrl`](tauri_utils::config::BuildConfig::dev_url) configuration value if it exsits.
pub(crate) fn get_url(&self, https: bool) -> Cow<'_, Url> { /// * 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).
match self.base_path() { /// * Returns [`Self::tauri_protocol_url`] (e.g. `tauri://localhost`) otherwise.
Some(url) => Cow::Borrowed(url), pub(crate) fn get_app_url(&self, https: bool) -> Cow<'_, Url> {
_ => self.protocol_url(https), #[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 +785,7 @@ mod test {
#[cfg(custom_protocol)] #[cfg(custom_protocol)]
{ {
assert_eq!( assert_eq!(
manager.get_url(false).to_string(), manager.get_app_url(false).to_string(),
if cfg!(windows) || cfg!(target_os = "android") { if cfg!(windows) || cfg!(target_os = "android") {
"http://tauri.localhost/" "http://tauri.localhost/"
} else { } else {
@ -798,7 +793,7 @@ mod test {
} }
); );
assert_eq!( assert_eq!(
manager.get_url(true).to_string(), manager.get_app_url(true).to_string(),
if cfg!(windows) || cfg!(target_os = "android") { if cfg!(windows) || cfg!(target_os = "android") {
"https://tauri.localhost/" "https://tauri.localhost/"
} else { } else {
@ -808,7 +803,10 @@ mod test {
} }
#[cfg(dev)] #[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 { struct EventSetup {

View File

@ -60,7 +60,7 @@ pub(crate) struct IpcJavascript<'a> {
pub struct UriSchemeProtocol<R: Runtime> { pub struct UriSchemeProtocol<R: Runtime> {
/// Handler for protocol /// Handler for protocol
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
pub protocol: pub handler:
Box<dyn Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>, Box<dyn Fn(UriSchemeContext<'_, R>, http::Request<Vec<u8>>, UriSchemeResponder) + Send + Sync>,
} }
@ -231,7 +231,7 @@ impl<R: Runtime> WebviewManager<R> {
app_handle: &app_handle, app_handle: &app_handle,
webview_label: webview_id, webview_label: webview_id,
}; };
(protocol.protocol)(context, request, UriSchemeResponder(responder)) (protocol.handler)(context, request, UriSchemeResponder(responder))
}); });
} }
@ -413,7 +413,7 @@ impl<R: Runtime> WebviewManager<R> {
#[allow(unused_mut)] // mut url only for the data-url parsing #[allow(unused_mut)] // mut url only for the data-url parsing
let mut url = match &pending.webview_attributes.url { let mut url = match &pending.webview_attributes.url {
WebviewUrl::App(path) => { 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) { let url = if PROXY_DEV_SERVER && is_local_network_url(&app_url) {
Cow::Owned(Url::parse("tauri://localhost").unwrap()) Cow::Owned(Url::parse("tauri://localhost").unwrap())
} else { } else {
@ -431,7 +431,7 @@ impl<R: Runtime> WebviewManager<R> {
} }
} }
WebviewUrl::External(url) => { 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 is_app_url = config_url.make_relative(url).is_some();
let mut url = url.clone(); let mut url = url.clone();
if is_app_url && PROXY_DEV_SERVER && is_local_network_url(&url) { if is_app_url && PROXY_DEV_SERVER && is_local_network_url(&url) {

View File

@ -17,7 +17,7 @@ use crate::{
/// <https://github.com/rust-lang/cargo/blob/46fa867ff7043e3a0545bf3def7be904e1497afd/crates/cargo-util/src/paths.rs#L73-L106> /// <https://github.com/rust-lang/cargo/blob/46fa867ff7043e3a0545bf3def7be904e1497afd/crates/cargo-util/src/paths.rs#L73-L106>
fn normalize_path(path: &Path) -> PathBuf { fn normalize_path(path: &Path) -> PathBuf {
let mut components = path.components().peekable(); 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(); components.next();
PathBuf::from(c.as_os_str()) PathBuf::from(c.as_os_str())
} else { } else {
@ -47,7 +47,7 @@ fn normalize_path(path: &Path) -> PathBuf {
/// <https://github.com/rust-lang/cargo/blob/46fa867ff7043e3a0545bf3def7be904e1497afd/crates/cargo-util/src/paths.rs#L73-L106> /// <https://github.com/rust-lang/cargo/blob/46fa867ff7043e3a0545bf3def7be904e1497afd/crates/cargo-util/src/paths.rs#L73-L106>
fn normalize_path_no_absolute(path: &Path) -> PathBuf { fn normalize_path_no_absolute(path: &Path) -> PathBuf {
let mut components = path.components().peekable(); 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(); components.next();
PathBuf::from(c.as_os_str()) PathBuf::from(c.as_os_str())
} else { } else {

View File

@ -642,13 +642,13 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
>( >(
mut self, mut self,
uri_scheme: N, uri_scheme: N,
protocol: H, protocol_handler: H,
) -> Self { ) -> Self {
self.uri_scheme_protocols.insert( self.uri_scheme_protocols.insert(
uri_scheme.into(), uri_scheme.into(),
Arc::new(UriSchemeProtocol { Arc::new(UriSchemeProtocol {
protocol: Box::new(move |ctx, request, responder| { handler: Box::new(move |ctx, request, responder| {
responder.respond(protocol(ctx, request)) responder.respond(protocol_handler(ctx, request))
}), }),
}), }),
); );
@ -712,12 +712,12 @@ impl<R: Runtime, C: DeserializeOwned> Builder<R, C> {
>( >(
mut self, mut self,
uri_scheme: N, uri_scheme: N,
protocol: H, protocol_handler: H,
) -> Self { ) -> Self {
self.uri_scheme_protocols.insert( self.uri_scheme_protocols.insert(
uri_scheme.into(), uri_scheme.into(),
Arc::new(UriSchemeProtocol { Arc::new(UriSchemeProtocol {
protocol: Box::new(protocol), handler: Box::new(protocol_handler),
}), }),
); );
self self

View File

@ -2,6 +2,8 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
//! Custom protocol handlers
#[cfg(feature = "protocol-asset")] #[cfg(feature = "protocol-asset")]
pub mod asset; pub mod asset;
#[cfg(feature = "isolation")] #[cfg(feature = "isolation")]

View File

@ -32,7 +32,7 @@ pub fn get<R: Runtime>(
#[cfg(all(dev, mobile))] #[cfg(all(dev, mobile))]
let url = { let url = {
let mut url = manager let mut url = manager
.get_url(window_origin.starts_with("https")) .get_app_url(window_origin.starts_with("https"))
.as_str() .as_str()
.to_string(); .to_string();
if url.ends_with('/') { if url.ends_with('/') {
@ -95,9 +95,9 @@ fn get_response<R: Runtime>(
let path = path let path = path
.strip_prefix("tauri://localhost") .strip_prefix("tauri://localhost")
.map(|p| p.to_string()) .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/*` // where `$P` is not `localhost/*`
.unwrap_or_else(|| "".to_string()); .unwrap_or_default();
let mut builder = HttpResponse::builder() let mut builder = HttpResponse::builder()
.add_configured_headers(manager.config.app.security.headers.as_ref()) .add_configured_headers(manager.config.app.security.headers.as_ref())

View File

@ -1682,7 +1682,7 @@ tauri::Builder::default()
// if from `tauri://` custom protocol // 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.scheme() == protocol_url.scheme()
&& current_url.domain() == protocol_url.domain() && current_url.domain() == protocol_url.domain()
}) || }) ||
@ -1690,7 +1690,7 @@ tauri::Builder::default()
// or if relative to `devUrl` or `frontendDist` // or if relative to `devUrl` or `frontendDist`
self self
.manager() .manager()
.get_url(uses_https) .get_app_url(uses_https)
.make_relative(current_url) .make_relative(current_url)
.is_some() .is_some()
@ -1706,7 +1706,7 @@ tauri::Builder::default()
// so we check using the first part of the domain // so we check using the first part of the domain
#[cfg(any(windows, target_os = "android"))] #[cfg(any(windows, target_os = "android"))]
let local = { 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 let maybe_protocol = current_url
.domain() .domain()
.and_then(|d| d .split_once('.')) .and_then(|d| d .split_once('.'))

View File

@ -797,28 +797,28 @@ impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
/// Window APIs. /// Window APIs.
impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> { impl<'a, R: Runtime, M: Manager<R>> WebviewWindowBuilder<'a, R, M> {
/// The initial position of the window's. /// The initial position of the window in logical pixels.
#[must_use] #[must_use]
pub fn position(mut self, x: f64, y: f64) -> Self { pub fn position(mut self, x: f64, y: f64) -> Self {
self.window_builder = self.window_builder.position(x, y); self.window_builder = self.window_builder.position(x, y);
self self
} }
/// Window size. /// Window size in logical pixels.
#[must_use] #[must_use]
pub fn inner_size(mut self, width: f64, height: f64) -> Self { pub fn inner_size(mut self, width: f64, height: f64) -> Self {
self.window_builder = self.window_builder.inner_size(width, height); self.window_builder = self.window_builder.inner_size(width, height);
self self
} }
/// Window min inner size. /// Window min inner size in logical pixels.
#[must_use] #[must_use]
pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { 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_builder = self.window_builder.min_inner_size(min_width, min_height);
self self
} }
/// Window max inner size. /// Window max inner size in logical pixels.
#[must_use] #[must_use]
pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { 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); self.window_builder = self.window_builder.max_inner_size(max_width, max_height);

View File

@ -808,28 +808,28 @@ impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
/// Window APIs. /// Window APIs.
#[cfg_attr(not(feature = "unstable"), allow(dead_code))] #[cfg_attr(not(feature = "unstable"), allow(dead_code))]
impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> { impl<'a, R: Runtime, M: Manager<R>> WindowBuilder<'a, R, M> {
/// The initial position of the window's. /// The initial position of the window in logical pixels.
#[must_use] #[must_use]
pub fn position(mut self, x: f64, y: f64) -> Self { pub fn position(mut self, x: f64, y: f64) -> Self {
self.window_builder = self.window_builder.position(x, y); self.window_builder = self.window_builder.position(x, y);
self self
} }
/// Window size. /// Window size in logical pixels.
#[must_use] #[must_use]
pub fn inner_size(mut self, width: f64, height: f64) -> Self { pub fn inner_size(mut self, width: f64, height: f64) -> Self {
self.window_builder = self.window_builder.inner_size(width, height); self.window_builder = self.window_builder.inner_size(width, height);
self self
} }
/// Window min inner size. /// Window min inner size in logical pixels.
#[must_use] #[must_use]
pub fn min_inner_size(mut self, min_width: f64, min_height: f64) -> Self { 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_builder = self.window_builder.min_inner_size(min_width, min_height);
self self
} }
/// Window max inner size. /// Window max inner size in logical pixels.
#[must_use] #[must_use]
pub fn max_inner_size(mut self, max_width: f64, max_height: f64) -> Self { 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); self.window_builder = self.window_builder.max_inner_size(max_width, max_height);

View File

@ -25,12 +25,12 @@
"identifier": "fs:allow-app", "identifier": "fs:allow-app",
"allow": [ "allow": [
{ {
"path": "$APP/**" "path": "$APPDATA/**"
} }
], ],
"deny": [ "deny": [
{ {
"path": "$APP/*.db" "path": "$APPDATA/*.db"
} }
] ]
}, },

View File

@ -1,8 +1,8 @@
[[permission]] [[permission]]
identifier = "allow-app" identifier = "allow-app"
description = "Allows accessing the $APP path." description = "Allows accessing the $APPDATA path."
[[permission.scope.allow]] [[permission.scope.allow]]
path = "$APP" path = "$APPDATA"
[[permission]] [[permission]]
identifier = "allow-download-dir" identifier = "allow-download-dir"

View File

@ -3,4 +3,4 @@ identifier = "deny-webview-folder-windows"
platforms = ["windows"] platforms = ["windows"]
description = "Denies access to the webview folder on Windows" description = "Denies access to the webview folder on Windows"
[[permission.scope.deny]] [[permission.scope.deny]]
path = "$APP/EBWebView/**" path = "$APPLOCALDATA/EBWebView/**"

View File

@ -398,7 +398,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP", "$APPDATA",
), ),
}, },
), ),

View File

@ -68,7 +68,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP", "$APPDATA",
), ),
}, },
), ),

View File

@ -310,7 +310,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP", "$APPDATA",
), ),
}, },
), ),

View File

@ -244,14 +244,14 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP/**", "$APPDATA/**",
), ),
}, },
), ),
Map( Map(
{ {
"path": String( "path": String(
"$APP", "$APPDATA",
), ),
}, },
), ),
@ -281,7 +281,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP/*.db", "$APPDATA/*.db",
), ),
}, },
), ),

View File

@ -208,7 +208,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP", "$APPDATA",
), ),
}, },
), ),

View File

@ -56,7 +56,7 @@ Resolved {
Map( Map(
{ {
"path": String( "path": String(
"$APP/EBWebView/**", "$APPLOCALDATA/EBWebView/**",
), ),
}, },
), ),

View File

@ -25,7 +25,7 @@
"example:api:dev": "pnpm run --filter \"api\" tauri dev" "example:api:dev": "pnpm run --filter \"api\" tauri dev"
}, },
"devDependencies": { "devDependencies": {
"prettier": "^3.5.3" "prettier": "^3.6.2"
}, },
"minimumReleaseAge": 4320, "minimumReleaseAge": 4320,
"packageManager": "pnpm@10.16.0", "packageManager": "pnpm@10.16.0",

View File

@ -1,5 +1,11 @@
# Changelog # 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] ## \[2.9.0]
### New Features ### New Features

View File

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/api", "name": "@tauri-apps/api",
"version": "2.9.0", "version": "2.9.1",
"description": "Tauri API definitions", "description": "Tauri API definitions",
"funding": { "funding": {
"type": "opencollective", "type": "opencollective",
@ -55,7 +55,7 @@
"eslint-plugin-security": "3.0.1", "eslint-plugin-security": "3.0.1",
"fast-glob": "3.3.3", "fast-glob": "3.3.3",
"globals": "^16.2.0", "globals": "^16.2.0",
"rollup": "4.53.2", "rollup": "4.54.0",
"tslib": "^2.8.1", "tslib": "^2.8.1",
"typescript": "^5.8.3", "typescript": "^5.8.3",
"typescript-eslint": "^8.34.1" "typescript-eslint": "^8.34.1"

View File

@ -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). * - 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 url?: string
/** The initial vertical position. */ /** The initial vertical position in logical pixels. */
x: number x: number
/** The initial horizontal position. */ /** The initial horizontal position in logical pixels. */
y: number y: number
/** The initial width. */ /** The initial width in logical pixels. */
width: number width: number
/** The initial height. */ /** The initial height in logical pixels. */
height: number height: number
/** /**
* Whether the webview is transparent or not. * Whether the webview is transparent or not.

View File

@ -2317,21 +2317,21 @@ interface PreventOverflowMargin {
interface WindowOptions { interface WindowOptions {
/** Show window in the center of the screen.. */ /** Show window in the center of the screen.. */
center?: boolean 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 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 y?: number
/** The initial width. */ /** The initial width in logical pixels. */
width?: number width?: number
/** The initial height. */ /** The initial height in logical pixels. */
height?: number 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 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 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 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 maxHeight?: number
/** /**
* Prevent the window from overflowing the working area (e.g. monitor size - taskbar size) * Prevent the window from overflowing the working area (e.g. monitor size - taskbar size)

View File

@ -1,5 +1,25 @@
# Changelog # 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] ## \[2.9.4]
### Bug Fixes ### Bug Fixes

View File

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/cli", "name": "@tauri-apps/cli",
"version": "2.9.4", "version": "2.9.6",
"description": "Command line interface for building Tauri apps", "description": "Command line interface for building Tauri apps",
"type": "commonjs", "type": "commonjs",
"funding": { "funding": {
@ -41,7 +41,7 @@
] ]
}, },
"devDependencies": { "devDependencies": {
"@napi-rs/cli": "^3.0.0", "@napi-rs/cli": "^3.4.1",
"@types/node": "^24.0.0", "@types/node": "^24.0.0",
"cross-env": "10.1.0", "cross-env": "10.1.0",
"vitest": "^4.0.0" "vitest": "^4.0.0"

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More