* fix(window-state): convert macOS coordinates to Logical to fix overlay shrink and multi-monitor DPI scaling drift
* chore: add changeset for logical coordinates and macOS overlay fix
* chore(window-state): fix change file package keys
* fix(window-state): save the macOS content rect size instead of guessing the title bar
The 20-40px outer/inner heuristic also matched ordinary decorated windows, saving their outer size so they grew by the title bar height on every restore. Derive the title bar height from the content rect instead, in one helper shared by update_state, the Resized handler and the initial metadata.
* fix(window-state): keep the saved state in physical pixels
State files written by earlier versions hold physical pixels, and logical coordinates are not one global space across monitors with different scale factors, so a position converted with one monitor's scale was restored on another. Converting with the window's scale at Moved time could also pick up a stale scale mid-drag, and an unavailable scale silently stored physical values as logical.
* fix(window-state): check the restored position against the monitors
For a maximized window the monitor check tested x and y, which are the monitor's corner, while the window was then placed at prev_x and prev_y. A window maximized after leaving a now-disconnected monitor passed the check and was restored off-screen.
* test(window-state): cover repeated size and position restores in e2e
Restores each window three times, also with an overlay title bar, and checks the inner and outer size (or position) still match the first save, so drift between saving and restoring accumulates and fails the test.
* chore(window-state): describe the restore fixes in the change file
* chore(deps): update @crabnebula/test-runner-backend to 0.3.1
0.3.0 returns a new-session response that WebdriverIO 10 rejects as not W3C, so every macOS e2e spec failed to create a session.
---------
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
* fix(deep-link): filter out web links instead of app links in deep link domains
This fixes a bug where on ios, deeplinks just don't work because the final Info.plist file doesn't have them.
And also used a better id for CFBundleURLName
Fixes regression from 2804803949
* feat(deep-link): add `webcredentials:` for iOS entitlements file
* chore: added changelog for deep-link patch
* add tests
* remove webcredentials
* -js
---------
Co-authored-by: Lucas Nogueira <lucas@tauri.app>
* 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>
* 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>
* 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>
* 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>
* 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>
`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
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).
In plugins/fs/src/commands.rs seek, `SeekFrom::Start(offset as u64)`
turned -1 into u64::MAX. The offset is now converted with u64::try_from
and a negative one is an error. E2E spec added.
In plugins/fs/guest-js/index.ts writeFile, the stream path opened the
file with {write, create} but no truncate, unlike the buffer path which
truncates unless `append` is set (commands.rs write_file_inner), so
shorter content left stale trailing bytes.
The stream path now passes `truncate: !options?.append`. api-iife.js
regenerated. E2E spec covers overwrite and append with a stream.
* fix(ci): Android e2e flakes, shell `Terminated` sent before output
- close "isn't responding" system dialogs before each spec and hide error dialogs on the CI emulator:
a launcher ANR dialog takes input focus from the app, and Android then denies clipboard reads
- retry switching to the webview context until it succeeds instead of running the spec in the
native context when the first switch fails with "No such context found"
- save the focused window, a screenshot and logcat when an Android test fails
- shell: wait for the pipe readers to finish before emitting `Terminated`; the readers took their
read lock on their own thread, so a child exiting quickly could have `close` emitted before
its output
* Apply suggestion from @lucasfernog
* fix(fs): report read errors of readTextFileLines
In plugins/fs/src/commands.rs read_text_file_lines_next, a read error was
mapped to "not done, empty line", so a persistent error such as EISDIR
(File::open of a directory succeeds on Unix) made the iterator yield ""
forever and the error was swallowed.
The command now closes the resource and returns the error; the JS iterator
resets its rid so a new iteration starts over. api-iife.js regenerated. E2E
spec iterates a directory and expects a rejection.
* fix(fs): close the file when a readTextFileLines loop exits early
In plugins/fs/guest-js/index.ts readTextFileLines, the async iterator did
not implement return(), so breaking out of a for await loop left the
StdLinesResource (an open file) in the webview resource table.
return() now closes the resource and resets the iterator. api-iife.js
regenerated. E2E spec breaks out of a loop, checks the resource id is no
longer valid and that iterating again starts over.
In plugins/fs/guest-js/index.ts, the size function only sent `path`
although the Rust command accepts `options.baseDir` and the JSDoc example
passed `{ baseDir: BaseDirectory.AppData }` (a TS error, silently dropped
at runtime, so the relative path was rejected).
Adds an optional `options?: SizeOptions` parameter (new exported type).
api-iife.js regenerated. The e2e spec now measures a file and a directory
relative to AppData instead of working around the missing option.
In plugins/fs/src/commands.rs write_file_inner, a malformed or non-ASCII
`options` header was dropped with .ok(), so baseDir/append/createNew were
silently ignored and the call became a truncating write to the raw path;
the JSON array body fallback truncated values above 255 and dropped
non-numbers.
The header is parsed with parse_write_file_options: empty, `undefined`
(what fetch sends for JSON.stringify(undefined)) and `null` mean no
options, anything else must parse. Array bodies must only contain bytes.
Unit test for the header parser; e2e spec for writes without options,
which is the case the `undefined` handling keeps working.