Commit Graph
2299 Commits
Author SHA1 Message Date
renovate[bot] eb27a7cf7f chore(deps): update dependency @zerodevx/svelte-json-view to v2.0.1 (#3705)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-15 19:19:49 -03:00
renovate[bot] 90694454fe chore(deps): update dependency rollup to v4.64.5 (#3706)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-15 19:18:56 -03:00
renovate[bot] 93c11642a3 chore(deps): update dependency typescript-eslint to v8.71.2 (#3714)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-15 19:18:34 -03:00
Fabian-Lars 463977675d fix(deep-link): compilation error with rust-ini 0.21.3 (#3711) 2026-10-15 19:18:16 -03:00
kxrn_gupta 6c9746e551 fix(single-instance): handle Windows startup race and ensure secondary instance exits (#3704) 2026-10-15 13:06:10 -03:00
FabianLars 6ea32db9a8 docs(sql): fix platform matrix 2026-10-15 10:13:39 +02:00
github-actions[bot]andLucas Nogueira 44293a5722 Publish New Versions (v2) (#3689)
* publish new versions

* torch 2.0.0

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
opener-js-v2.7.2 persisted-scope-v2.4.2 single-instance-v2.5.4 notification-js-v2.7.0 geolocation-js-v2.5.0 deep-link-js-v2.6.2 updater-js-v2.14.0 dialog-js-v2.8.3 clipboard-manager-js-v2.5.0 biometric-v2.5.0 geolocation-v2.5.0 fs-js-v2.7.1 http-v2.8.3 sql-js-v2.6.0 deep-link-v2.6.2 barcode-scanner-js-v2.5.3 opener-v2.7.2 notification-v2.7.0 updater-v2.14.0 biometric-js-v2.5.0 dialog-v2.8.3 clipboard-manager-v2.5.0 barcode-scanner-v2.5.3 http-js-v2.8.3 sql-v2.6.0 fs-v2.7.1
2026-10-14 15:17:54 -03:00
Lucas Nogueira 7550f7cdb3 chore(deps): bump rustls to 0.23.46 2026-10-14 13:36:20 -03:00
36d8e4098e feat(geolocation): support for non-GMS devices (#3377)
* chore(geolocation): update gradle

* feat(geolocation): add support for android devices without GMS

* fix(geolocation): watchPosition does not resolve on android

* feat(example): add watch support for geolocation

* chore: add changeset

* Update .changes/geolocation-non-gms.md

Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>

* fix(geolocation): only use Android Location API on API Level >= 31

* fix resolve

* fix(geolocation): use LocationManagerCompat for non-GMS devices

- support API 24+ instead of only API 31+
- pick the best enabled provider (fused, gps, network) instead of GPS only
- honor enableHighAccuracy in getCurrentPosition
- clear the previous listener before starting a new watch
- report an error when the provider is disabled during a watch
- share the provider/priority logic between both code paths
- drop the geolocation-js bump, no JS changes

* fix(examples): clear existing geolocation watch before starting a new one

* chore(geolocation): add change file for watchPosition resolve fix

* fix(geolocation): honor enableHighAccuracy in getCurrentPosition on Android 12+ without GMS

* fix(geolocation): fall back to the next provider when one returns no fix on Android without GMS

* fix(geolocation): honor timeout in getCurrentPosition on Android

* fix(geolocation): keep multiple watchPosition watches active on Android

* chore(geolocation): bump geolocation-js alongside geolocation in change files

* refactor(geolocation): report provider errors from the callers of androidProviders

* e2e tests

---------

Co-authored-by: Tony <68118705+Legend-Master@users.noreply.github.com>
Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-13 17:37:39 -03:00
Umut DağandLucas Nogueira 57297f3fb1 feat(clipboard-manager): add support for writing secrets (#3376)
* feat(clipboard-manager): add support for writing secrets

add `write_secret` command that writes a text into the clipboard and
hints clipboard managers to not save the text.

uses `arboard`'s `SetExtLinux`, `SetExtWindows`, and `SetExtApple`
extensions for each platform.

* fix(clipboard-manager): require arboard 3.6

* chore(clipboard-manager): add license header to secret.rs

* fix(clipboard-manager): only exclude from monitoring on Windows

* refactor(clipboard-manager): replace ExcludeSecret trait with a function

* chore(clipboard-manager): drop redundant cfg(desktop) in desktop.rs

* refactor(clipboard-manager): share clipboard access in a helper

* feat(clipboard-manager): implement write_secret on Android and iOS

* docs(clipboard-manager): document writeSecret

* chore(clipboard-manager): add change file for writeSecret

* test(clipboard-manager): cover writeSecret in e2e

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-13 17:37:11 -03:00
shouyuandLucas Nogueira 1ab930465f fix(opener): avoid blocking-runtime panic in reveal_item_in_dir (#3565)
* fix(opener): avoid blocking-runtime panic in reveal_item_in_dir

* fix(opener): run zbus reveal on a dedicated thread for all callers

Move the runtime-panic fix into the Linux/BSD implementation so the
public Rust APIs are covered too, not just the JS command, and propagate
the spawn_blocking join error via the existing Tauri error variant.

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-13 14:44:22 -03:00
Christopher PruijsenandLucas Nogueira 0e17675653 fix(http): decode header values as ISO-8859-1 (#3586)
* fix(http): decode response header values as ISO-8859-1

Response header values were decoded with String::from_utf8 before being
sent over IPC. Raw UTF-8 bytes produced JS strings with code points
above 255, which new Headers() rejects as invalid ByteStrings
("Type error" on WebKit), and bytes that were not valid UTF-8 failed
the fetch outright. Decode as ISO-8859-1 instead so every byte maps to a
char 0-255, matching what browsers expose for the same response.

Fixes #2898

* fix(http): add tests for ISO-8859-1 response header decoding

Cover the #2898 Content-Disposition case and non-UTF-8 header bytes on
the same conversion fetch_send uses, so a revert to UTF-8 fails the suite.

* request headers, e2e test

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-13 14:43:50 -03:00
kxrn_gupta 62b3565fb5 chore(deps): update quinn-proto (lockfile-only) (#3707)
Updates quinn-proto from 0.11.14 to 0.11.19 to resolve recent security advisories (RUSTSEC-2026-0338, RUSTSEC-2026-0339, RUSTSEC-2026-0340, RUSTSEC-2026-0342).
2026-10-13 14:23:53 +02:00
0xbizkandLucas Nogueira d80b1be257 feat: add torch plugin for iOS and Android (#3551)
* feat(barcode-scanner): add torch toggle

* feat: torch plugin

* fix

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-13 05:37:04 -03:00
kxrn_guptaandLucas Nogueira c91a9e6af5 feat(sql): add autoCreate option to Database.load (#3702)
* feat(sql): add autoCreate option to Database.load

Add utoCreate option to Database.load allowing users to disable implicit database creation when loading a database.

Closes #299

* fix(sql): fix unused variable without a database feature

* refactor(sql): share the database existence check between drivers

* fix(sql): don't report a failed existence check as a missing database

* fix(sql): name the database as passed, without password, in the missing database error

* fix(sql): don't create the app config dir when autoCreate is false

* refactor(sql): use the LoadOptions default for missing options

* test(sql): cover autoCreate and password redaction

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-12 10:46:00 -03:00
Charles SchaeferandLucas Nogueira 0374bec1e2 [feat] [biometric] Adding the capability of encrypting/decrypting data using biometric authentication on Android (Ref. #2306) (#2454)
* –feat: adding the ability to encrypt/decrypt data based on the biometric auth

Adding the method biometricCipher() that allows to use the biometric authentication to use a generated key from android that can be accessed only through the biometric authentication. The method uses this key to encrypt/decrypt the data provided by the caller in the "options" parameter, with "dataToEncrypt" or "dataToDecrypt" filled.

Changes were done both on Kotlin, Rust and JS sides.

* Improving the way we encrypt data by allowing only if the biometric was successful.

* Adding a warning on the JS side

* Adding doc changes in readme.md

* Adding doc changes in readme.md

* Update README.md - it was updated incomplete

* update docs

* enhance error handling

* update example

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-12 10:38:16 -03:00
Shreyash Gupta b3e52ce036 fix(barcode-scanner): settle the pending scan() promise on cancel (fix #3560) (#3571)
On Android, cancel() called destroy() first, and destroy() sets
savedInvoke to null, so the savedInvoke?.reject("cancelled") that
follows was a no-op. The pending scan() promise was never settled and
callers awaiting it were stranded, which is especially bad in windowed
mode where the page background stays transparent.

Reject the pending invoke before tearing the camera down, matching the
order the iOS implementation already uses.
2026-10-12 10:32:41 -03:00
renovate[bot] de501ac3b0 chore(deps): update dependency rollup to v4.64.3 (#3697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-12 10:31:03 -03:00
kxrn_gupta f8296d038f fix(fs): pass require_literal_leading_dot when initializing runtime scope (#3701)
When initializing the plugin's runtime scope in .setup, pass 
equire_literal_leading_dot from config to FsScope::Scope instead of using FsScope::default() so that paths allowed dynamically via s_scope().allow_directory() inherit the configured value.

Closes #3699
2026-10-12 10:30:21 -03:00
BestCodesandLucas Nogueira 4356356dab fix: keep GNOME notifications open (fix #2566) (#3588)
* experimenting...

Signed-off-by: BestCodes <106822363+The-Best-Codes@users.noreply.github.com>

* omit unconfirmed fact from .changes

Signed-off-by: BestCodes <106822363+The-Best-Codes@users.noreply.github.com>

* fix(notification): send untracked Linux notifications on the shared connection

Holding notify-rust's handle with `on_close` blocked an async runtime
worker until the server closed the notification, and opened a D-Bus
connection per notification. Since GNOME keeps notifications in its tray,
a handful of them could stall every async task of the app.

Send every notification on the connection the plugin already keeps open
for its action listener instead: it keeps the sender's name alive for
GNOME at the cost of a single connection and thread, and the listener
runs the `on_close` callbacks.

* fix(notification): offer `on_close` on the BSDs too

The BSDs share the D-Bus implementation with Linux, including the GNOME
issue, so gate `NotificationBuilder::on_close` like the rest of that
implementation and document when the callback runs.

* fix(notification): run `on_close` without the tracker lock held

The callback ran on the listener thread while the guard of the callback
map was alive, and a panic in it ended that thread, which then reported
no action of any notification for the rest of the app's life. Take the
callback out of the map before running it and contain its panics.

* fix(notification): use the covector package names in the change files

`tauri-plugin-notification` and `@tauri-apps/plugin-notification` are
not packages of .changes/config.json, so covector refused the change
file. Use `notification` and `notification-js`, and record the new
`on_close` API as a feature of its own.

Also let `on_close` take an `FnOnce`, since it runs at most once.

---------

Signed-off-by: BestCodes <106822363+The-Best-Codes@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-12 09:46:43 -03:00
Lucas Fernandes NogueiraandAmr Bashir 8efe845612 chore: add AGENTS.md (#3680)
* chore: add AGENTS.md

* Apply batched suggestions from code review [skip ci]

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>

* simplify

---------

Co-authored-by: Amr Bashir <amr.bashir2015@gmail.com>
2026-10-11 22:07:25 -03:00
Patrick F.andLucas Nogueira dff0dd4b23 fix(biometric) Incorrect error reported on Android with no device passcode set and fallback allowed (#2648)
* Fix incorrect error being reported in certain cases with fallback allowed

* Add change file

* Rework original solution due to overlooking authenticators logic on API >= `Build.VERSION_CODES.R`

* fix(biometric): don't cast the Android error message to String

* fix(biometric): report a missing device credential before showing the Android prompt

Replaces the override of ERROR_NO_BIOMETRICS in the prompt callback, which keyed on
the caller's flag rather than the device state and missed the no-hardware errors.

* fix(biometric): load the missing device credential message from a string resource

* chore(biometric): drop stray semicolon

* docs(biometric): mention the passcodeNotSet error code rename in the change file

* test(e2e): cover the biometric passcodeNotSet rejection on Android

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-11 21:56:38 -03:00
Masayoshi TakahashiandLucas Nogueira 2ebe54abce feat(biometric): add macOS Touch ID support via LocalAuthentication framework (#3264)
* feat(biometric): add macOS Touch ID support via LocalAuthentication framework

* cleanup

* fmt

* change file

* fix tests

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-11 21:56:15 -03:00
Lucas Fernandes Nogueira a819187e12 fix(updater): don't mutate the caller's options in the JS API (#3690)
`convertToRustHeaders` replaced `options.headers` of the object passed to
`check`, `download` and `downloadAndInstall` with an array of entries. The
headers are now converted into the invoke payload only (`toRustHeaders`).

E2E: `check` leaves the options object untouched.

plugins/updater/guest-js/index.ts
2026-10-11 16:17:29 -03:00
Lucas Fernandes Nogueira 24e6451b11 fix(updater): fall back to the next temp location for AppImage updates (#3693)
- `tempdir_in(..)?` and `metadata()?` returned early on the first location
  that failed (e.g. a non-writable `/tmp`), so the cache dir and the
  directory next to the AppImage were never tried. Failures now move on to
  the next location, as the deb/rpm path already did.
- The candidate list was duplicated between the AppImage and deb/rpm paths;
  both now use `tmp_dir_locations`, which also no longer unwraps the parent
  of the app path (`extract_path.parent().unwrap()`).

Compile-checked with clippy in a Linux container (default features).

plugins/updater/src/updater.rs
2026-10-11 16:14:50 -03:00
Lucas Fernandes Nogueira 21ebe1f531 fix(updater): derive the Windows installer launch error from ShellExecuteW (#3692)
* fix(updater): derive the Windows installer launch error from ShellExecuteW

A failed `ShellExecuteW` was reported with `std::io::Error::last_os_error()`,
but `ShellExecuteW` reports failures through its return value (`SE_ERR_*`),
not reliably through `GetLastError`, so the message could be meaningless. The
return value is now mapped to an error (the codes shared with Win32 errors,
like `SE_ERR_ACCESSDENIED` when the UAC prompt is declined, keep their OS
message).

Running `on_before_exit` only once the installer launched changes when a
public hook runs and is left for v3.

Compile-checked only (clippy for x86_64-pc-windows-msvc).

plugins/updater/src/updater.rs

* use constants
2026-10-11 16:12:34 -03:00
Lucas Fernandes Nogueira 7b7c7c6251 fix(updater): release the previous download when downloading again (#3691)
Each `Update.download()` overwrote `this.downloadedBytes` without closing the
previous resource, so the whole previous update payload stayed in the webview
resources table. The previous resource is now closed once the new download
succeeded (so a failed retry still leaves the earlier download installable).

Not covered by e2e: the fixture manifest has no valid signature, so a
download can never succeed there.

plugins/updater/guest-js/index.ts
2026-10-11 16:11:59 -03:00
Lucas Fernandes Nogueira d057ec4736 fix(updater): warn when the update download URL is not https (#3694)
* fix(updater): warn when the update download URL is not https

`validate_endpoints` enforces `https` for the endpoints, but not for the `url`
of the manifest, so the artifact can be downloaded in plaintext. Enforcing it
would break existing releases (left for v3); `Update::download` now logs a
warning instead, unless `dangerousInsecureTransportProtocol` is enabled.

plugins/updater/src/updater.rs

* Apply suggestion from @lucasfernog
2026-10-11 16:11:41 -03:00
Lucas Fernandes Nogueira 4b1ba07943 fix(updater): report install as unsupported on mobile (#3695)
`#[cfg(mobile)] fn install_inner` returned `Ok(())` without doing anything.
`check` already fails with `UnsupportedOs` there unless a Rust caller sets a
custom target, in which case a download was followed by a successful
"install" that did nothing. It now returns `Error::UnsupportedOs`, the error
`check` uses.

Verified with clippy for aarch64-linux-android (the iOS build needs the Swift
package, which does not build here).

plugins/updater/src/updater.rs
2026-10-11 16:05:25 -03:00
Lucas Fernandes Nogueira f2af373b6a fix(updater): check the AppImage update payload before installing it (#3696)
* fix(updater): check the AppImage update payload before installing it

Without the `zip` feature the gz check was compiled out and a signed
`.tar.gz` was written verbatim over the AppImage, and any other payload
without the gz magic (e.g. a `.deb` from the same release, or the fallthrough
when `bundle_type()` is `None`) was written the same way, corrupting the app.

The payload is now checked before the current AppImage is moved: a gzip
archive requires the `zip` feature, and anything else must be an ELF
executable (which every AppImage is); otherwise `InvalidUpdaterFormat` is
returned. The `Cursor`/`OsStr` imports are gated so that the crate builds
warning-free without `zip` on Linux too.

Compile-checked with clippy on macOS, Linux (container) and Windows, each
with and without the `zip` feature.

plugins/updater/src/updater.rs

* tests
2026-10-11 16:05:01 -03:00
Vincent KocandLucas Nogueira 2d541bc0d1 fix(deep-link): preserve XDG registration ownership and report failures (#3585)
* fix(deep-link): honor XDG failures and unregister associations

* test(deep-link): isolate other application handlers

* chore: satisfy release metadata and test header checks

* fix(deep-link): gate XDG helpers to Linux

The plugin only supports Linux, so FreeBSD builds warned about dead code.

* refactor(deep-link): add run_command helper

Share the spawn, status check and logging for XDG commands.

* refactor(deep-link): share desktop file list helpers

register and unregister now edit MimeType lists the same way.

* fix(deep-link): keep desktop file quoting on register

Parse raw values so a quoted Exec matches and isn't rewritten each time.

* fix(deep-link): clean mimeapps.list first on unregister

A failing update-desktop-database no longer leaves the app as the default.

* fix(deep-link): keep mimeapps.list comments on unregister

Edit it line by line instead of re-serializing it through rust-ini.

* fix(deep-link): skip cache refresh when nothing to unregister

Only run update-desktop-database if the desktop file changed or the cache still lists the app.

* fix(deep-link): treat no default handler as unregistered

xdg-mime exits with 4 on KDE and LXQt when no handler is set.

* fix(deep-link): tolerate padded xdg-mime query output

Compare the trimmed first line instead of the raw output.

* test(deep-link): run XDG tests in CI

Drop #[ignore], skip when the tools are missing, and install them on Linux CI.

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-11 06:19:37 -03:00
Vincent KocandLucas Nogueira f83c5d3b0f fix(single-instance): propagate D-Bus setup and handoff errors (#3584)
* fix(single-instance): propagate D-Bus setup and handoff errors

* chore: satisfy release metadata and test header checks

* fix(single-instance): launch normally without a D-Bus session bus

Log a warning instead of failing setup when the session bus is unreachable, and add context to handoff errors.

* ci: run the single-instance D-Bus test under dbus-run-session

Run it in test-rust on Linux and keep it out of the updater integration job, which has no session bus.

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-11 06:18:21 -03:00
Lucas Fernandes Nogueira 6a263bec1c fix(fs): allow open, seek and fstat in the write permission sets (#3630)
* fix(fs): allow open, seek and fstat in the write permission sets

The stream path of writeFile calls `open`, which only the nested command
list of `allow-write-file` granted (plugins/fs/permissions/write-all.toml,
write-files.toml), so `fs:allow-appdata-write-recursive` and the other
write sets rejected streamed writes; seek/fstat were missing for
FileHandles created under these sets.

Adds open, seek and fstat to write-all and write-files. This widens the
write sets slightly (open is already implied by allow-write-file); the
generated reference does not list set members, so nothing to regenerate.

* use dependencies instead
2026-10-10 16:06:43 -03:00
renovate[bot] db25585357 chore(deps): update dependency rollup to v4.64.1 (#3685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2026-10-10 16:06:19 -03:00
Lucas Fernandes Nogueira 3b19ca096c fix(fs): do not parse relative paths with a colon as URLs (#3632)
In plugins/fs/src/file_path.rs SafeFilePath::from_str, any string that
parsed as a URL with a scheme of 2+ characters was a URL, so a relative
path such as `notes:2024.txt` became a cannot-be-a-base URL and failed
with InvalidPathUrl.

Cannot-be-a-base URLs are now parsed as paths. The scheme-agnostic
url.to_file_path() stays: its result is scope checked (not a bypass).
Unit test for the parser; e2e spec writes and reads such a file (not on
Windows, where `:` is not allowed in file names).
2026-10-10 16:06:02 -03:00
Den IlinandLucas Fernandes Nogueira b6f39cc51c fix(updater): don't fail AppImage installs when the temp dir is another mount of the same file system (#3688)
* fix(updater): skip a backup location the AppImage cannot be renamed into

Two mounts of one file system share st_dev, so install_appimage could
pick a bind-mounted or private temp dir and then fail every install with
EXDEV. Move on to the next location instead; the last one is the
AppImage's own directory.

* Apply suggestion from @lucasfernog

---------

Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
2026-10-10 14:46:00 -03:00
t8y2andLucas Nogueira fce235c3fb feat(updater): restore cached updates and verify package bytes (#3640)
* feat(updater): restore cached updates and verify package bytes

* fix(updater): keep cached update tests in the existing module

* require signed version, verify bytes, cleanup

* fix bump

* fmt

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-10 14:12:13 -03:00
Lucas Fernandes Nogueira b53d198461 fix(single-instance): do not rely on | as arg separator on Windows (#3686) 2026-10-10 13:57:51 -03:00
Lucas Nogueira 659f222742 fix: clippy 2026-10-10 13:11:31 -03:00
github-actions[bot] 6bbd44d4ef publish new versions (#3675)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
global-shortcut-js-v2.4.1 global-shortcut-v2.4.1 http-js-v2.8.2 updater-js-v2.13.3 http-v2.8.2 clipboard-manager-v2.4.2 log-js-v2.10.1 haptics-v2.4.2 log-v2.10.1 clipboard-manager-js-v2.4.2 haptics-js-v2.4.2 nfc-js-v2.4.2 nfc-v2.4.2 notification-js-v2.6.0 biometric-v2.4.2 notification-v2.6.0 opener-js-v2.7.1 opener-v2.7.1 fs-js-v2.7.0 persisted-scope-v2.4.1 barcode-scanner-v2.5.2 biometric-js-v2.4.2 geolocation-v2.4.2 fs-v2.7.0 shell-js-v2.5.0 updater-v2.13.3 geolocation-js-v2.4.2 single-instance-v2.5.3 shell-v2.5.0 dialog-js-v2.8.2 dialog-v2.8.2 barcode-scanner-js-v2.5.2
2026-10-10 12:50:18 -03:00
hassan fc18d05513 fix(global-shortcut): release the shortcuts lock before running handlers (#3683) 2026-10-10 17:58:11 +03:00
42ae8b4501 fix(ios): make init_plugin_* entry points public so release builds link on Xcode 27 (#3684)
* fix(ios): make `init_plugin_*` entry points public so release builds link on Xcode 27

Xcode 27's SwiftPM (Swift Build) gives non-public @_cdecl functions local
visibility in release builds, so each plugin's init_plugin_* is undefined
when Rust links. Mark them public in the 11 plugins with an iOS part.

See tauri-apps/tauri#16130

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

* Apply suggestion from @lucasfernog

---------

Co-authored-by: takakix2 <1370181+takakix2@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Lucas Fernandes Nogueira <lucas@tauri.app>
2026-10-10 08:09:53 -03:00
justanotheranonymoususerandLucas Nogueira 818d2e04d9 fix(single-instance): limit second instance's wait on Windows (#3645)
* Update windows.rs

* Create single-instance-forward-timeout.md

* use SMTO_NORMAL

* nit

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-09 15:25:33 -03:00
justanotheranonymoususerandLucas Nogueira 323fe80df1 fix(single-instance): forward non-Unicode arguments and cwd (#3644)
* Update windows.rs

* Create single-instance-non-unicode-args.md

* fix on linux and windows too

---------

Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-09 15:25:15 -03:00
Lucas Nogueira 677258138b test(e2e): fix __name usage on FS test 2026-10-09 15:17:53 -03:00
Lucas Nogueira 46f7c878a0 chore: fmt 2026-10-09 15:08:52 -03:00
a8acd178bd feat(shell): add process group spawn option (fix #1332) (#3351)
* feat(shell): add process group spawn option (fix #1332)

Add a `processGroup` boolean option to the shell plugin's spawn command.
When enabled, the child process is spawned in its own process group (POSIX)
or job object (Windows) using the `process-wrap` crate, so that killing
the child also kills the entire process tree.

This fixes the issue where programs like PyInstaller wrappers spawn a
child process that gets orphaned when Tauri kills the parent.

* test(shell): add PyInstaller simulation tests for process group kill

Add end-to-end tests that reproduce the exact scenario from issue #1332:
a wrapper process (like PyInstaller's bootloader) spawns a grandchild.

- Without process_group: killing the wrapper orphans the grandchild
- With process_group: killing the wrapper also kills the grandchild

* refactor(shell): drop redundant cfg gates, trim process-wrap features

Address review feedback on #3351:

- Remove `#[cfg(any(unix, windows))]` gates on `ChildKind::ProcessGroup`,
  the kill/pid match arms, and the spawn block, plus the now-dead
  `#[cfg(not(any(unix, windows)))]` fallback. That cfg only excluded wasm,
  which this plugin never builds for.
- Set `default-features = false` on process-wrap and enable only the
  features actually used: std, process-group (unix), creation-flags and
  job-object (windows). Drops kill-on-drop, process-session, and tracing.

* fix(shell): enable process-wrap tracing feature, fix CI formatting and changefile

- Add `tracing` feature to process-wrap: with default-features = false its
  Windows job_object.rs calls `debug\!` unconditionally while the import is
  gated behind `#[cfg(feature = "tracing")]`, failing the Windows build with
  "cannot find macro `debug`".
- Reformat process/mod.rs assertions to satisfy `cargo fmt --check`.
- Reindent the process-wrap features array to 2 spaces for taplo.
- Use covector package keys (`shell` / `shell-js`) in the change file so the
  check-change-files and covector status jobs pass.

* refactor(shell): unify child handling on process-wrap, drop SharedChild

Collapse the ChildKind enum and the per-platform GroupChild types into a
single process-wrap-backed child. The command always spawns through
StdCommandWrap; the process_group flag is now just an optional wrapper
rather than a switch into a separate child type.

This drops the shared_child dependency and resolves two review notes:
the Unix path no longer hand-rolls killpg, and kill() now goes through
process-wrap's kill (start_kill + wait), which reaps the entire process
group instead of only signalling it.

A background thread polls try_wait to surface the exit status, since
process-wrap's wrappers only expose &mut self wait methods (the reason
SharedChild was used on Unix in the first place).

* chore(example): add process group toggle to shell view

* fix(shell): pass typed creation flags to process-wrap on Windows

`process_wrap::std::CreationFlags` is a newtype over the `windows` crate's
`PROCESS_CREATION_FLAGS`, not a raw `u32`, so the Windows build failed to
compile. Depend on `windows` (already in the tree via `tauri`, pinned to the
same 0.61 that `process-wrap` links against) and use its `CREATE_NO_WINDOW`
constant, which drops the hand-rolled magic number.

The wrap is still required: `JobObject::pre_spawn` calls `creation_flags` and
would otherwise clobber the `CREATE_NO_WINDOW` set at construction.

* perf(shell): block on child exit instead of polling try_wait

The switch from `SharedChild` to `process-wrap` moved the child behind a
mutex, since `StdChildWrapper`'s wait methods take `&mut self` while both
the wait thread and `CommandChild::kill()` need access. A blocking wait
would hold the lock for the child's whole lifetime and starve `kill()`,
so the wait thread polled `try_wait` every 10ms instead.

Block on the raw process outside the lock using a wait that does not reap
(`waitid` with `WNOWAIT` on unix, `WaitForSingleObject` on windows), then
take the lock once to let process-wrap collect the exit status. This is
the same technique shared_child uses internally, applied on top of
process-wrap's kill/reap semantics. No new dependencies or Cargo features
are required.

`kill()` reaps the child while holding the lock, so the raw wait can lose
that race and return ECHILD. That means the exit status is already cached
in the wrapper, so it is treated as success and the status is collected
via `try_wait`. Without this guard, a stress test of 300 spawn+kill
cycles produced 36 Error events in place of Terminated; with it, none in
900 cycles. The `try_wait` loop stays as a defensive fallback, though in
practice the first call succeeds immediately.

Mean latency for `Command::output()` on macOS (debug, 30 iterations of
`echo`) drops from 13.22ms to ~1.8ms, and 10 idle 5s children cost ~11ms
CPU total instead of ~75ms with the poll loop.

* fix(shell): keep CREATE_NO_WINDOW on process-group children (windows)

process-wrap's CreationFlags/JobObject coordination is broken during
spawn (watchexec/process-wrap#35): JobObject::pre_spawn cannot see the
CreationFlags wrapper, so it overwrote our flags with just
CREATE_SUSPENDED and process-group children flashed a console window.

Register CreationFlags(CREATE_SUSPENDED | CREATE_NO_WINDOW) after
JobObject so its pre_spawn runs last and wins. CREATE_SUSPENDED is kept
so the child cannot spawn grandchildren before job assignment; the same
upstream bug keeps wrap_child's resume check from seeing it, so the
child is still resumed.

* test(shell): run the process-tree kill tests on windows

Add a powershell variant of the pyinstaller simulation script and lift
the unix-only gates on the process-group tests, so the windows job in
test-rust exercises the job-object spawn/kill path instead of skipping
it. Both pyinstaller tests now also assert that a Terminated event is
still delivered after kill().

* Update plugins/shell/src/process/mod.rs

Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>

* Update .changes/shell-process-group.md

Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>

* Update plugins/shell/src/process/mod.rs

Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>

* Delete .changes/shell-wait-no-poll.md

* refactor(shell): replace process-wrap with shared_child and an inlined job object

Use std process groups on unix and a job object on windows, with
shared_child handling wait and kill on all platforms.

* fix(shell): kill the process group even after its leader exited

CommandChild::kill returned early once the direct child had been reaped,
so killpg/TerminateJobObject never ran and anything the child left running
in its process group or job object survived, including on app exit.

Adds a launcher-style test (the child starts a grandchild and exits) that
runs on Windows, Linux and macOS.

* fix(shell): restore Debug on CommandChild

Dropping the derive was a breaking change for downstream types that derive
Debug and hold a CommandChild.

* fix(shell): don't block the main thread in the kill command

CommandChild::kill now waits for the child to exit, and the sync kill
command ran it on the main thread while still holding the children lock.
Make the command async and release the lock before killing.

---------

Co-authored-by: Fabian-Lars <30730186+FabianLars@users.noreply.github.com>
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
2026-10-09 15:08:15 -03:00
Lucas Fernandes Nogueira e03dca60e7 fix(fs): accept absolute paths in the iOS security-scope commands (#3628)
In plugins/fs/src/commands.rs, start/stop_accessing_security_scoped_resource
only handled SafeFilePath::Url, so a plain path was a silent no-op
although the JS docs say "path or file:// URL" (and
Fs::stop_accessing_security_scoped_resource accepts paths).

Absolute paths are now converted to file:// URLs first; relative paths keep
being ignored. iOS-only code: formatted but not compiled here (the iOS
tauri build script fails in this environment).
2026-10-09 13:25:05 -03:00
Lucas Fernandes Nogueira 3a9000177c fix(fs): resolve symlinks of missing paths before checking the scope (#3627)
In plugins/fs/src/commands.rs resolve_path / is_forbidden, only paths
that already existed were canonicalized, so a new file below a symlinked
directory in the scope was matched by its unresolved path and written
outside of the scope. Relative symlink targets were resolved against the
process CWD, only the link target was checked against deny patterns, and
resolution errors made is_forbidden fail open.

resolve_path now computes the real path (canonical nearest existing
ancestor + remaining components, following dangling symlinks relative to
their parent, bounded to 40 links) and checks it against the allow and deny
patterns; deny patterns also match the path as given. Resolution errors
fail closed. Unit tests cover symlinked ancestors, relative and dangling
links and loops.
2026-10-09 13:21:34 -03:00
Lucas Fernandes Nogueira f81f0447cc fix(fs): read uncompressed Android assets from the cache copy (#3635)
In plugins/fs/android/src/main/java/FsPlugin.kt getFileDescriptor, for
uncompressed assets AssetManager.openFd returns an AssetFileDescriptor
whose parcel descriptor is the whole APK; its startOffset/length were
dropped and Rust read from offset 0, i.e. APK bytes. Only compressed
assets (openFd throws) took the cache copy path.

All assets now use the cache copy path. The cache file path is also checked
to stay below cacheDir/_assets. Kotlin not compiled here: unverified, needs
an on-device check.
2026-10-09 13:20:34 -03:00