Merge branch 'v2' into feature/fallback_targets

This commit is contained in:
Krzysztof Andrelczyk
2025-07-21 16:26:50 +02:00
45 changed files with 1396 additions and 844 deletions
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## \[2.4.0]
- [`aa9140e1`](https://github.com/tauri-apps/plugins-workspace/commit/aa9140e1ac239ab9f015f92b2ed52bbf0eda7c12) ([#2437](https://github.com/tauri-apps/plugins-workspace/pull/2437) by [@enkhjile](https://github.com/tauri-apps/plugins-workspace/../../enkhjile)) Added support for GS1 DataBar on iOS 15.4+
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-barcode-scanner"
version = "2.3.0"
version = "2.4.0"
description = "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS"
edition = { workspace = true }
authors = { workspace = true }
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-barcode-scanner",
"version": "2.3.0",
"version": "2.4.0",
"description": "Scan QR codes, EAN-13 and other kinds of barcodes on Android and iOS",
"license": "MIT OR Apache-2.0",
"authors": [
+3 -3
View File
@@ -10,12 +10,12 @@
"tauri": "tauri"
},
"dependencies": {
"@tauri-apps/api": "2.6.0",
"@tauri-apps/api": "2.7.0",
"@tauri-apps/plugin-deep-link": "2.4.0"
},
"devDependencies": {
"@tauri-apps/cli": "2.6.2",
"@tauri-apps/cli": "2.7.0",
"typescript": "^5.7.3",
"vite": "^6.2.6"
"vite": "^7.0.4"
}
}
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## \[2.3.1]
### Dependencies
- Upgraded to `fs-js@2.4.1`
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-dialog"
version = "2.3.0"
version = "2.3.1"
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
edition = { workspace = true }
authors = { workspace = true }
@@ -34,7 +34,7 @@ tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
url = { workspace = true }
tauri-plugin-fs = { path = "../fs", version = "2.4.0" }
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
[target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true, features = ["wry"] }
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-dialog",
"version": "2.3.0",
"version": "2.3.1",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## \[2.4.1]
- [`44a1f659`](https://github.com/tauri-apps/plugins-workspace/commit/44a1f659125a341191420e650608b0b6ff316a0e) ([#2846](https://github.com/tauri-apps/plugins-workspace/pull/2846) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `writeFile` doesn't create a new file by default when the data is a `ReadableStream`
## \[2.4.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-fs"
version = "2.4.0"
version = "2.4.1"
description = "Access the file system."
authors = { workspace = true }
license = { workspace = true }
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1074,7 +1074,7 @@ async function writeFile(
}
if (data instanceof ReadableStream) {
const file = await open(path, options)
const file = await open(path, { create: true, ...options })
const reader = data.getReader()
try {
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-fs",
"version": "2.4.0",
"version": "2.4.1",
"description": "Access the file system.",
"license": "MIT OR Apache-2.0",
"authors": [
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## \[2.5.1]
### Dependencies
- Upgraded to `fs-js@2.4.1`
## \[2.5.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-http"
version = "2.5.0"
version = "2.5.1"
description = "Access an HTTP client written in Rust."
edition = { workspace = true }
authors = { workspace = true }
@@ -34,7 +34,7 @@ serde_json = { workspace = true }
tauri = { workspace = true }
thiserror = { workspace = true }
tokio = { version = "1", features = ["sync", "macros"] }
tauri-plugin-fs = { path = "../fs", version = "2.4.0" }
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
urlpattern = "0.3"
regex = "1"
http = "1"
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-http",
"version": "2.5.0",
"version": "2.5.1",
"license": "MIT OR Apache-2.0",
"authors": [
"Tauri Programme within The Commons Conservancy"
+6
View File
@@ -1,5 +1,11 @@
# Changelog
## \[2.3.1]
### Dependencies
- Upgraded to `fs@2.4.1`
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+2 -2
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-persisted-scope"
version = "2.3.0"
version = "2.3.1"
description = "Save filesystem and asset scopes and restore them when the app is reopened."
authors = { workspace = true }
license = { workspace = true }
@@ -27,7 +27,7 @@ log = { workspace = true }
thiserror = { workspace = true }
aho-corasick = "1"
bincode = "1"
tauri-plugin-fs = { path = "../fs", version = "2.4.0" }
tauri-plugin-fs = { path = "../fs", version = "2.4.1" }
[features]
protocol-asset = ["tauri/protocol-asset"]
+5
View File
@@ -1,5 +1,10 @@
# Changelog
## \[2.3.1]
- [`6f345870`](https://github.com/tauri-apps/plugins-workspace/commit/6f345870df4e7b187deb869df03b79858e03b4fe) ([#2860](https://github.com/tauri-apps/plugins-workspace/pull/2860) by [@MorpheusXAUT](https://github.com/tauri-apps/plugins-workspace/../../MorpheusXAUT)) Fix D-Bus name replacement logic on Linux to prevent multiple instances from acquiring the same well-known name.\
This patch updates the `zbus` dependency to the latest compatible version (`^5.9`) and explicitly sets `RequestNameFlags` to ensure a second instance fails to acquire the D-Bus name when another one is already running.
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-single-instance"
version = "2.3.0"
version = "2.3.1"
description = "Ensure a single instance of your tauri app is running."
authors = { workspace = true }
license = { workspace = true }
@@ -9,6 +9,6 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@tauri-apps/cli": "2.6.2"
"@tauri-apps/cli": "2.7.0"
}
}
@@ -61,6 +61,8 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
.unwrap()
.name(dbus_name.as_str())
.unwrap()
.replace_existing_names(false)
.allow_name_replacements(false)
.serve_at(dbus_path.as_str(), single_instance_dbus)
.unwrap()
.build()
@@ -8,8 +8,8 @@
"tauri": "tauri"
},
"devDependencies": {
"@tauri-apps/cli": "2.6.2",
"@tauri-apps/cli": "2.7.0",
"typescript": "^5.7.3",
"vite": "^6.2.6"
"vite": "^7.0.4"
}
}
+5
View File
@@ -1,5 +1,10 @@
# Changelog
## \[2.3.1]
- [`b7292030`](https://github.com/tauri-apps/plugins-workspace/commit/b7292030594daa04e78979214478031241b6e38e) ([#2838](https://github.com/tauri-apps/plugins-workspace/pull/2838) by [@velocitysystems](https://github.com/tauri-apps/plugins-workspace/../../velocitysystems)) Fix `download` and `upload` locks main thread on Android.
Use Tokio to spawn task when invoking commands.
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-upload"
version = "2.3.0"
version = "2.3.1"
description = "Upload files from disk to a remote server over HTTP."
authors = { workspace = true }
license = { workspace = true }
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-upload",
"version": "2.3.0",
"version": "2.3.1",
"description": "Upload files from disk to a remote server over HTTP.",
"license": "MIT OR Apache-2.0",
"authors": [
+152 -70
View File
@@ -66,99 +66,106 @@ struct ProgressPayload {
#[command]
async fn download(
url: &str,
file_path: &str,
url: String,
file_path: String,
headers: HashMap<String, String>,
body: Option<String>,
on_progress: Channel<ProgressPayload>,
) -> Result<()> {
let client = reqwest::Client::new();
let mut request = if let Some(body) = body {
client.post(url).body(body)
} else {
client.get(url)
};
// Loop trought the headers keys and values
// and add them to the request object.
for (key, value) in headers {
request = request.header(&key, value);
}
tokio::spawn(async move {
let client = reqwest::Client::new();
let mut request = if let Some(body) = body {
client.post(&url).body(body)
} else {
client.get(&url)
};
// Loop trought the headers keys and values
// and add them to the request object.
for (key, value) in headers {
request = request.header(&key, value);
}
let response = request.send().await?;
if !response.status().is_success() {
return Err(Error::HttpErrorCode(
response.status().as_u16(),
response.text().await.unwrap_or_default(),
));
}
let total = response.content_length().unwrap_or(0);
let response = request.send().await?;
if !response.status().is_success() {
return Err(Error::HttpErrorCode(
response.status().as_u16(),
response.text().await.unwrap_or_default(),
));
}
let total = response.content_length().unwrap_or(0);
let mut file = BufWriter::new(File::create(file_path).await?);
let mut stream = response.bytes_stream();
let mut file = BufWriter::new(File::create(&file_path).await?);
let mut stream = response.bytes_stream();
let mut stats = TransferStats::default();
while let Some(chunk) = stream.try_next().await? {
file.write_all(&chunk).await?;
stats.record_chunk_transfer(chunk.len());
let _ = on_progress.send(ProgressPayload {
progress: chunk.len() as u64,
progress_total: stats.total_transferred,
total,
transfer_speed: stats.transfer_speed,
});
}
file.flush().await?;
Ok(())
let mut stats = TransferStats::default();
while let Some(chunk) = stream.try_next().await? {
file.write_all(&chunk).await?;
stats.record_chunk_transfer(chunk.len());
let _ = on_progress.send(ProgressPayload {
progress: chunk.len() as u64,
progress_total: stats.total_transferred,
total,
transfer_speed: stats.transfer_speed,
});
}
file.flush().await?;
Ok(())
})
.await
.map_err(|e| Error::Io(std::io::Error::other(e.to_string())))?
}
#[command]
async fn upload(
url: &str,
file_path: &str,
url: String,
file_path: String,
headers: HashMap<String, String>,
on_progress: Channel<ProgressPayload>,
) -> Result<String> {
// Read the file
let file = File::open(file_path).await?;
let file_len = file.metadata().await.unwrap().len();
tokio::spawn(async move {
// Read the file
let file = File::open(&file_path).await?;
let file_len = file.metadata().await.unwrap().len();
// Create the request and attach the file to the body
let client = reqwest::Client::new();
let mut request = client
.post(url)
.header(reqwest::header::CONTENT_LENGTH, file_len)
.body(file_to_body(on_progress, file));
// Create the request and attach the file to the body
let client = reqwest::Client::new();
let mut request = client
.post(&url)
.header(reqwest::header::CONTENT_LENGTH, file_len)
.body(file_to_body(on_progress, file, file_len));
// Loop through the headers keys and values
// and add them to the request object.
for (key, value) in headers {
request = request.header(&key, value);
}
// Loop through the headers keys and values
// and add them to the request object.
for (key, value) in headers {
request = request.header(&key, value);
}
let response = request.send().await?;
if response.status().is_success() {
response.text().await.map_err(Into::into)
} else {
Err(Error::HttpErrorCode(
response.status().as_u16(),
response.text().await.unwrap_or_default(),
))
}
let response = request.send().await?;
if response.status().is_success() {
response.text().await.map_err(Into::into)
} else {
Err(Error::HttpErrorCode(
response.status().as_u16(),
response.text().await.unwrap_or_default(),
))
}
})
.await
.map_err(|e| Error::Io(std::io::Error::other(e.to_string())))?
}
fn file_to_body(channel: Channel<ProgressPayload>, file: File) -> reqwest::Body {
fn file_to_body(channel: Channel<ProgressPayload>, file: File, file_len: u64) -> reqwest::Body {
let stream = FramedRead::new(file, BytesCodec::new()).map_ok(|r| r.freeze());
let mut stats = TransferStats::default();
reqwest::Body::wrap_stream(ReadProgressStream::new(
stream,
Box::new(move |progress, total| {
Box::new(move |progress, _total| {
stats.record_chunk_transfer(progress as usize);
let _ = channel.send(ProgressPayload {
progress,
progress_total: stats.total_transferred,
total,
total: file_len,
transfer_speed: stats.transfer_speed,
});
}),
@@ -183,9 +190,9 @@ mod tests {
}
#[tokio::test]
async fn should_error_if_status_not_success() {
async fn should_error_on_download_if_status_not_success() {
let mocked_server = spawn_server_mocked(400).await;
let result = download_file(&mocked_server.url).await;
let result = download_file(mocked_server.url).await;
mocked_server.mocked_endpoint.assert();
assert!(result.is_err());
}
@@ -193,7 +200,7 @@ mod tests {
#[tokio::test]
async fn should_download_file_successfully() {
let mocked_server = spawn_server_mocked(200).await;
let result = download_file(&mocked_server.url).await;
let result = download_file(mocked_server.url).await;
mocked_server.mocked_endpoint.assert();
assert!(
result.is_ok(),
@@ -202,8 +209,53 @@ mod tests {
);
}
async fn download_file(url: &str) -> Result<()> {
let file_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test/test.txt");
#[tokio::test]
async fn should_error_on_upload_if_status_not_success() {
let mocked_server = spawn_upload_server_mocked(500).await;
let result = upload_file(mocked_server.url).await;
mocked_server.mocked_endpoint.assert();
assert!(result.is_err());
match result.unwrap_err() {
Error::HttpErrorCode(status, _) => assert_eq!(status, 500),
_ => panic!("Expected HttpErrorCode error"),
}
}
#[tokio::test]
async fn should_error_on_upload_if_file_not_found() {
let mocked_server = spawn_upload_server_mocked(200).await;
let file_path = "/nonexistent/file.txt".to_string();
let headers = HashMap::new();
let sender: Channel<ProgressPayload> =
Channel::new(|msg: InvokeResponseBody| -> tauri::Result<()> {
let _ = msg;
Ok(())
});
let result = upload(mocked_server.url, file_path, headers, sender).await;
assert!(result.is_err());
match result.unwrap_err() {
Error::Io(_) => {}
_ => panic!("Expected IO error for missing file"),
}
}
#[tokio::test]
async fn should_upload_file_successfully() {
let mocked_server = spawn_upload_server_mocked(200).await;
let result = upload_file(mocked_server.url).await;
mocked_server.mocked_endpoint.assert();
assert!(
result.is_ok(),
"failed to upload file: {}",
result.unwrap_err()
);
let response_body = result.unwrap();
assert_eq!(response_body, "upload successful");
}
async fn download_file(url: String) -> Result<()> {
let file_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test/test.txt").to_string();
let headers = HashMap::new();
let sender: Channel<ProgressPayload> =
Channel::new(|msg: InvokeResponseBody| -> tauri::Result<()> {
@@ -213,6 +265,17 @@ mod tests {
download(url, file_path, headers, None, sender).await
}
async fn upload_file(url: String) -> Result<String> {
let file_path = concat!(env!("CARGO_MANIFEST_DIR"), "/test/test.txt").to_string();
let headers = HashMap::new();
let sender: Channel<ProgressPayload> =
Channel::new(|msg: InvokeResponseBody| -> tauri::Result<()> {
let _ = msg;
Ok(())
});
upload(url, file_path, headers, sender).await
}
async fn spawn_server_mocked(return_status: usize) -> MockedServer {
let mut _server = Server::new_async().await;
let path = "/mock_test";
@@ -230,4 +293,23 @@ mod tests {
mocked_endpoint: mock,
}
}
async fn spawn_upload_server_mocked(return_status: usize) -> MockedServer {
let mut _server = Server::new_async().await;
let path = "/upload_test";
let mock = _server
.mock("POST", path)
.with_status(return_status)
.with_body("upload successful")
.match_header("content-length", "20")
.create_async()
.await;
let url = _server.url() + path;
MockedServer {
_server,
url,
mocked_endpoint: mock,
}
}
}
@@ -9,9 +9,9 @@
"preview": "vite preview"
},
"devDependencies": {
"@tauri-apps/cli": "2.6.2",
"@tauri-apps/cli": "2.7.0",
"typescript": "^5.7.3",
"vite": "^6.2.6"
"vite": "^7.0.4"
},
"dependencies": {
"tauri-plugin-websocket-api": "link:..\\.."
+4
View File
@@ -1,5 +1,9 @@
# Changelog
## \[2.4.0]
- [`6a8f2558`](https://github.com/tauri-apps/plugins-workspace/commit/6a8f25587852b958a9e48b8c2e8884cc94a7dc7f) ([#2619](https://github.com/tauri-apps/plugins-workspace/pull/2619) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Making `flags` optional in the `saveWindowState`, `restoreState`, `restoreStateCurrent` JavaScripts APIs, leaving it empty will make it use plugin's default flags
## \[2.3.0]
- [`f209b2f2`](https://github.com/tauri-apps/plugins-workspace/commit/f209b2f23cb29133c97ad5961fb46ef794dbe063) ([#2804](https://github.com/tauri-apps/plugins-workspace/pull/2804) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated tauri to 2.6
+1 -1
View File
@@ -1,6 +1,6 @@
[package]
name = "tauri-plugin-window-state"
version = "2.3.0"
version = "2.4.0"
description = "Save window positions and sizes and restore them when the app is reopened."
authors = { workspace = true }
license = { workspace = true }
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@tauri-apps/plugin-window-state",
"version": "2.3.0",
"version": "2.4.0",
"description": "Save window positions and sizes and restore them when the app is reopened.",
"license": "MIT OR Apache-2.0",
"authors": [