Merge branch 'v2' into download-progress-speed

pull/1797/head
Artaza Sameen 9 months ago committed by GitHub
commit 337df4b83d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
"sql-js": patch
---
Fixed incorrect documentation of the select method in the Database class.

@ -0,0 +1,5 @@
---
"clipboard-manager": patch
---
Fix that `read_image` wrongly set the image rgba data with binary PNG data.

@ -1,6 +0,0 @@
---
"dialog": patch
"dialog-js": patch
---
Set `save` dialog mime type from the `filters` extensions on Android.

@ -1,6 +0,0 @@
---
"positioner": patch
"positioner-js": patch
---
Added missing permission for `handleIconState` and fixed its event processing logic.

@ -0,0 +1,5 @@
---
sql: patch
---
Replace `Mutex` with `RwLock` to enable concurrent SQL execution.

@ -0,0 +1,5 @@
---
"fs-js": "patch"
---
Fix `writeTextFile` converting UTF-8 characters (for example `äöü`) in the given path into replacement character (`<60>`)

@ -1,6 +0,0 @@
---
"http": "patch"
"http-js": "patch"
---
Allow skipping sending `Origin` header in HTTP requests by setting `Origin` header to an empty string when calling `fetch`.

@ -1,6 +0,0 @@
---
"http": "patch"
"http-js": "patch"
---
Retain headers order.

@ -0,0 +1,5 @@
---
log-plugin: patch
---
**Potentially breaking:** Updated `fern` from 0.6 to 0.7. This is technically a breaking change because `fern` is re-exported in `tauri-plugin-log`.

@ -1,6 +0,0 @@
---
"shell": "patch"
"shell-js": "patch"
---
On Windows, Fix `open` JS API hanging and freezing the app.

@ -1,7 +0,0 @@
---
"store-js": minor:feat
---
- Add `getStore`
- Add an option to use pre-stored (de)serialize functions (registered on rust)
- Add `LazyStore`

@ -1,23 +0,0 @@
---
"store": minor:breaking
---
### Breaking changes:
- Renamed `StoreCollection` to `StoreState`
- `StoreBuilder::build` now returns a `Result`
- `StoreExt::store` now returns `Result<Arc<Store>>`
### Enhancements:
- Save and cancel pending auto save on drop
- Use absolute path as store's key, fix #984
- Share store to resource table by default
- Enable auto save with 100ms debounce time by default
- Use pretty json by default, close #1690
### New features:
- Add `get_store` to get shared stores across js and rust side
- Add default (de)serialize functions settings `default_serialize_fn` and `default_deserialize_fn`
- Allow js to use pre-stored (de)serialize functions registered by `register_serialize_fn` and `register_deserialize_fn`

756
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -11,7 +11,7 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
log = "0.4" log = "0.4"
tauri = { version = "2.0.2", default-features = false } tauri = { version = "2.0.4", default-features = false }
tauri-build = "2.0.1" tauri-build = "2.0.1"
tauri-plugin = "2.0.1" tauri-plugin = "2.0.1"
tauri-utils = "2.0.1" tauri-utils = "2.0.1"

@ -1,16 +1,22 @@
# Official Tauri Plugins
This repo and all plugins require a Rust version of at least **1.77.2**
## Plugins Found Here ## Plugins Found Here
| | | Win | Mac | Lin | iOS | And | | | | Win | Mac | Lin | iOS | And |
| ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | --- | --- | --- | | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- | --- | --- | --- | --- |
| [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ? | ? | | [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ❌ | ❌ |
| [barcode-scanner](plugins/barcode-scanner) | Allows your mobile application to use the camera to scan QR codes, EAN-13 and other kinds of barcodes. | ? | ? | ? | ✅ | ✅ | | [barcode-scanner](plugins/barcode-scanner) | Allows your mobile application to use the camera to scan QR codes, EAN-13 and other kinds of barcodes. | ? | ? | ? | ✅ | ✅ |
| [biometric](plugins/biometric) | Prompt the user for biometric authentication on Android and iOS. | ? | ? | ? | ✅ | ✅ | | [biometric](plugins/biometric) | Prompt the user for biometric authentication on Android and iOS. | ? | ? | ? | ✅ | ✅ |
| [cli](plugins/cli) | Parse arguments from your Command Line Interface | ✅ | ✅ | ✅ | ? | ? | | [cli](plugins/cli) | Parse arguments from your Command Line Interface | ✅ | ✅ | ✅ | ❌ | ❌ |
| [clipboard-manager](plugins/clipboard-manager) | Read and write to the system clipboard. | ✅ | ✅ | ✅ | ✅ | ✅ | | [clipboard-manager](plugins/clipboard-manager) | Read and write to the system clipboard. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [deep-link](plugins/deep-link) | Set your Tauri application as the default handler for an URL. | ✅ | ✅ | ✅ | ✅ | ✅ | | [deep-link](plugins/deep-link) | Set your Tauri application as the default handler for an URL. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [dialog](plugins/dialog) | Native system dialogs for opening and saving files along with message dialogs. | ✅ | ✅ | ✅ | ✅ | ✅ | | [dialog](plugins/dialog) | Native system dialogs for opening and saving files along with message dialogs. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [fs](plugins/fs) | Access the file system. | ✅ | ✅ | ✅ | ? | ? | | [fs](plugins/fs) | Access the file system. | ✅ | ✅ | ✅ | ? | ? |
| [geolocation](plugins/geolocation) | Get and track current device position. | ? | ? | ? | ✅ | ✅ |
| [global-shortcut](plugins/global-shortcut) | Register global shortcuts. | ✅ | ✅ | ✅ | ? | ? | | [global-shortcut](plugins/global-shortcut) | Register global shortcuts. | ✅ | ✅ | ✅ | ? | ? |
| [haptics](plugins/haptics) | Haptic feedback and vibrations. | ? | ? | ? | ✅ | ✅ |
| [http](plugins/http) | Access the HTTP client written in Rust. | ✅ | ✅ | ✅ | ✅ | ✅ | | [http](plugins/http) | Access the HTTP client written in Rust. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? | | [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? |
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ | | [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
@ -18,19 +24,21 @@
| [notification](plugins/notification) | Send message notifications (brief auto-expiring OS window element) to your user. Can also be used with the Notification Web API. | ✅ | ✅ | ✅ | ✅ | ✅ | | [notification](plugins/notification) | Send message notifications (brief auto-expiring OS window element) to your user. Can also be used with the Notification Web API. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [os](plugins/os) | Read information about the operating system. | ✅ | ✅ | ✅ | ✅ | ✅ | | [os](plugins/os) | Read information about the operating system. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? | | [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ? | ? | | [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ❌ | ❌ |
| [process](plugins/process) | This plugin provides APIs to access the current process. To spawn child processes, see the [`shell`](https://github.com/tauri-apps/tauri-plugin-shell) plugin. | ✅ | ✅ | ✅ | ? | ? | | [process](plugins/process) | This plugin provides APIs to access the current process. To spawn child processes, see the [`shell`](https://github.com/tauri-apps/tauri-plugin-shell) plugin. | ✅ | ✅ | ✅ | ? | ? |
| [shell](plugins/shell) | Access the system shell. Allows you to spawn child processes and manage files and URLs using their default application. | ✅ | ✅ | ✅ | ? | ? | | [shell](plugins/shell) | Access the system shell. Allows you to spawn child processes and manage files and URLs using their default application. | ✅ | ✅ | ✅ | ? | ? |
| [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ? | ✅ | ? | ? | | [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ✅ | ✅ | ❌ | ❌ |
| [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | ? | | [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | |
| [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ✅ | ✅ | | [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? | | [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? |
| [updater](plugins/updater) | In-app updates for Tauri applications. | ✅ | ✅ | ✅ | ? | ? | | [updater](plugins/updater) | In-app updates for Tauri applications. | ✅ | ✅ | ✅ | ❌ | ❌ |
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? | | [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? |
| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? | | [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
| [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ? | ? | | [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ❌ | ❌ |
_This repo and all plugins require a Rust version of at least **1.77.2**_ - ✅: (Partially) Supported
- ❌: Not supported
- `?` : Unknown/Untested or Planned
## Contributing ## Contributing

@ -1,5 +1,15 @@
# Changelog # Changelog
## \[2.0.1]
### Dependencies
- Upgraded to `dialog-js@2.0.1`
- Upgraded to `fs-js@2.0.1`
- Upgraded to `http-js@2.0.1`
- Upgraded to `shell-js@2.0.1`
- Upgraded to `store-js@2.1.0`
## \[2.0.0] ## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release. - [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.

@ -1,7 +1,7 @@
{ {
"name": "svelte-app", "name": "svelte-app",
"private": true, "private": true,
"version": "2.0.0", "version": "2.0.1",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --clearScreen false", "dev": "vite --clearScreen false",
@ -9,33 +9,33 @@
"serve": "vite preview" "serve": "vite preview"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.0.2", "@tauri-apps/api": "2.0.3",
"@tauri-apps/plugin-barcode-scanner": "2.0.0", "@tauri-apps/plugin-barcode-scanner": "2.0.0",
"@tauri-apps/plugin-biometric": "2.0.0", "@tauri-apps/plugin-biometric": "2.0.0",
"@tauri-apps/plugin-cli": "2.0.0", "@tauri-apps/plugin-cli": "2.0.0",
"@tauri-apps/plugin-clipboard-manager": "2.0.0", "@tauri-apps/plugin-clipboard-manager": "2.0.0",
"@tauri-apps/plugin-dialog": "2.0.0", "@tauri-apps/plugin-dialog": "2.0.1",
"@tauri-apps/plugin-fs": "2.0.0", "@tauri-apps/plugin-fs": "2.0.1",
"@tauri-apps/plugin-geolocation": "2.0.0", "@tauri-apps/plugin-geolocation": "2.0.0",
"@tauri-apps/plugin-global-shortcut": "2.0.0", "@tauri-apps/plugin-global-shortcut": "2.0.0",
"@tauri-apps/plugin-haptics": "2.0.0", "@tauri-apps/plugin-haptics": "2.0.0",
"@tauri-apps/plugin-http": "2.0.0", "@tauri-apps/plugin-http": "2.0.1",
"@tauri-apps/plugin-nfc": "2.0.0", "@tauri-apps/plugin-nfc": "2.0.0",
"@tauri-apps/plugin-notification": "2.0.0", "@tauri-apps/plugin-notification": "2.0.0",
"@tauri-apps/plugin-os": "2.0.0", "@tauri-apps/plugin-os": "2.0.0",
"@tauri-apps/plugin-process": "2.0.0", "@tauri-apps/plugin-process": "2.0.0",
"@tauri-apps/plugin-shell": "2.0.0", "@tauri-apps/plugin-shell": "2.0.1",
"@tauri-apps/plugin-store": "2.0.0", "@tauri-apps/plugin-store": "2.1.0",
"@tauri-apps/plugin-updater": "2.0.0", "@tauri-apps/plugin-updater": "2.0.0",
"@zerodevx/svelte-json-view": "1.0.11" "@zerodevx/svelte-json-view": "1.0.11"
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/codicon": "^1.1.37", "@iconify-json/codicon": "^1.1.37",
"@iconify-json/ph": "^1.1.8", "@iconify-json/ph": "^1.1.8",
"@sveltejs/vite-plugin-svelte": "^3.0.1", "@sveltejs/vite-plugin-svelte": "^4.0.0",
"@tauri-apps/cli": "2.0.2", "@tauri-apps/cli": "2.0.4",
"@unocss/extractor-svelte": "^0.63.0", "@unocss/extractor-svelte": "^0.63.0",
"svelte": "^4.2.19", "svelte": "^5.0.0",
"unocss": "^0.63.0", "unocss": "^0.63.0",
"vite": "^5.4.7" "vite": "^5.4.7"
} }

@ -1,5 +1,23 @@
# Changelog # Changelog
## \[2.0.4]
### Dependencies
- Upgraded to `fs@2.0.3`
- Upgraded to `dialog@2.0.3`
- Upgraded to `http@2.0.3`
## \[2.0.3]
### Dependencies
- Upgraded to `dialog@2.0.2`
- Upgraded to `fs@2.0.2`
- Upgraded to `http@2.0.2`
- Upgraded to `shell@2.0.2`
- Upgraded to `store@2.1.0`
## \[2.0.2] ## \[2.0.2]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.

@ -1,7 +1,7 @@
[package] [package]
name = "api" name = "api"
publish = false publish = false
version = "2.0.2" version = "2.0.4"
description = "An example Tauri Application showcasing the api" description = "An example Tauri Application showcasing the api"
edition = "2021" edition = "2021"
rust-version = { workspace = true } rust-version = { workspace = true }
@ -20,21 +20,21 @@ serde = { workspace = true }
tiny_http = "0.12" tiny_http = "0.12"
log = { workspace = true } log = { workspace = true }
tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.1" } tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.1" }
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.1", features = [ tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.3", features = [
"watch", "watch",
] } ] }
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.1" } tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.1" }
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.1" } tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.3" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ tauri-plugin-http = { path = "../../../plugins/http", features = [
"multipart", "multipart",
], version = "2.0.1" } ], version = "2.0.3" }
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.1", features = [ tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.1", features = [
"windows7-compat", "windows7-compat",
] } ] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.1" } tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.1" }
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.1" } tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.1" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.1" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.2" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.0.1" } tauri-plugin-store = { path = "../../../plugins/store", version = "2.1.0" }
[dependencies.tauri] [dependencies.tauri]
workspace = true workspace = true

@ -53,6 +53,7 @@
} }
] ]
}, },
"shell:allow-open",
"shell:allow-kill", "shell:allow-kill",
"shell:allow-stdin-write", "shell:allow-stdin-write",
"process:allow-exit", "process:allow-exit",

@ -9,6 +9,8 @@
"updater:default", "updater:default",
"global-shortcut:allow-unregister", "global-shortcut:allow-unregister",
"global-shortcut:allow-register", "global-shortcut:allow-register",
"global-shortcut:allow-unregister-all" "global-shortcut:allow-unregister-all",
{ "identifier": "fs:allow-watch", "allow": ["*", "**/*"] },
"fs:allow-unwatch"
] ]
} }

@ -205,7 +205,7 @@
if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight
} }
// this function is renders HTML without sanitizing it so it's insecure // this function renders HTML without sanitizing it so it's insecure
// we only use it with our own input data // we only use it with our own input data
async function insecureRenderHtml(html) { async function insecureRenderHtml(html) {
messages.update((r) => [ messages.update((r) => [
@ -334,42 +334,46 @@
children:h-100% children:w-12 children:inline-flex children:h-100% children:w-12 children:inline-flex
children:items-center children:justify-center" children:items-center children:justify-center"
> >
<span <button
aria-label="Toggle dark mode"
title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'} title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleDark} on:click={toggleDark}
> >
{#if isDark} {#if isDark}
<div class="i-ph-sun" /> <div class="i-ph-sun"></div>
{:else} {:else}
<div class="i-ph-moon" /> <div class="i-ph-moon"></div>
{/if} {/if}
</span> </button>
<span <button
aria-label="Minimize window"
title="Minimize" title="Minimize"
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={minimize} on:click={minimize}
> >
<div class="i-codicon-chrome-minimize" /> <div class="i-codicon-chrome-minimize"></div>
</span> </button>
<span <button
aria-label="Maximize window"
title={isWindowMaximized ? 'Restore' : 'Maximize'} title={isWindowMaximized ? 'Restore' : 'Maximize'}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleMaximize} on:click={toggleMaximize}
> >
{#if isWindowMaximized} {#if isWindowMaximized}
<div class="i-codicon-chrome-restore" /> <div class="i-codicon-chrome-restore"></div>
{:else} {:else}
<div class="i-codicon-chrome-maximize" /> <div class="i-codicon-chrome-maximize"></div>
{/if} {/if}
</span> </button>
<span <button
aria-label="Close window"
title="Close" title="Close"
class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText" class="bg-inherit border-none hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
on:click={close} on:click={close}
> >
<div class="i-codicon-chrome-close" /> <div class="i-codicon-chrome-close"></div>
</span> </button>
</span> </span>
</div> </div>
{/if} {/if}
@ -377,13 +381,13 @@
<!-- Sidebar toggle, only visible on small screens --> <!-- Sidebar toggle, only visible on small screens -->
<div <div
id="sidebarToggle" id="sidebarToggle"
class="z-2000 sidebar-toggle display-none lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8 class="z-2000 sidebar-toggle hidden lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8
bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark" bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark"
> >
{#if isSideBarOpen} {#if isSideBarOpen}
<span class="i-codicon-close animate-duration-300ms animate-fade-in" /> <span class="i-codicon-close animate-duration-300ms animate-fade-in"></span>
{:else} {:else}
<span class="i-codicon-menu animate-duration-300ms animate-fade-in" /> <span class="i-codicon-menu animate-duration-300ms animate-fade-in"></span>
{/if} {/if}
</div> </div>
@ -395,24 +399,21 @@
class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999 class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999
bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2" bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2"
> >
<img <a href="https://tauri.app" target="_blank">
on:click={() => open('https://tauri.app/')} <img class="p-7" src="tauri_logo.png" alt="Tauri logo" />
class="self-center p-7 cursor-pointer" </a>
src="tauri_logo.png"
alt="Tauri logo"
/>
{#if !isWindows} {#if !isWindows}
<a href="##" class="nv justify-between h-8" on:click={toggleDark}> <a href="##" class="nv justify-between h-8" on:click={toggleDark}>
{#if isDark} {#if isDark}
Switch to Light mode Switch to Light mode
<div class="i-ph-sun" /> <div class="i-ph-sun"></div>
{:else} {:else}
Switch to Dark mode Switch to Dark mode
<div class="i-ph-moon" /> <div class="i-ph-moon"></div>
{/if} {/if}
</a> </a>
<br /> <br />
<div class="bg-white/5 h-2px" /> <div class="bg-white/5 h-2px"></div>
<br /> <br />
{/if} {/if}
@ -422,7 +423,7 @@
href="https://tauri.app/v1/guides/" href="https://tauri.app/v1/guides/"
> >
Documentation Documentation
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<a <a
class="nv justify-between h-8" class="nv justify-between h-8"
@ -430,7 +431,7 @@
href="https://github.com/tauri-apps/tauri" href="https://github.com/tauri-apps/tauri"
> >
GitHub GitHub
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<a <a
class="nv justify-between h-8" class="nv justify-between h-8"
@ -438,10 +439,10 @@
href="https://github.com/tauri-apps/tauri/tree/dev/examples/api" href="https://github.com/tauri-apps/tauri/tree/dev/examples/api"
> >
Source Source
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<br /> <br />
<div class="bg-white/5 h-2px" /> <div class="bg-white/5 h-2px"></div>
<br /> <br />
<div <div
class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1" class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1"
@ -456,7 +457,7 @@
isSideBarOpen = false isSideBarOpen = false
}} }}
> >
<div class="{view.icon} mr-2" /> <div class="{view.icon} mr-2"></div>
<p>{view.label}</p></a <p>{view.label}</p></a
> >
{/if} {/if}
@ -485,21 +486,23 @@
id="console" id="console"
class="select-none h-15rem grid grid-rows-[2px_2rem_1fr] gap-1 overflow-hidden" class="select-none h-15rem grid grid-rows-[2px_2rem_1fr] gap-1 overflow-hidden"
> >
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div <div
on:mousedown={startResizingConsole} on:mousedown={startResizingConsole}
class="bg-black/20 h-2px cursor-ns-resize" class="bg-black/20 h-2px cursor-ns-resize"
/> ></div>
<div class="flex justify-between items-center px-2"> <div class="flex justify-between items-center px-2">
<p class="font-semibold">Console</p> <p class="font-semibold">Console</p>
<div <button
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center aria-label="Clear Console"
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center border-none bg-inherit
hover:bg-hoverOverlay dark:hover:bg-darkHoverOverlay hover:bg-hoverOverlay dark:hover:bg-darkHoverOverlay
active:bg-hoverOverlay/25 dark:active:bg-darkHoverOverlay/25 active:bg-hoverOverlay/25 dark:active:bg-darkHoverOverlay/25
" "
on:click={clear} on:click={clear}
> >
<div class="i-codicon-clear-all" /> <div class="i-codicon-clear-all"></div>
</div> </button>
</div> </div>
<div <div
bind:this={consoleTextEl} bind:this={consoleTextEl}

@ -5,8 +5,9 @@
import 'uno.css' import 'uno.css'
import './app.css' import './app.css'
import App from './App.svelte' import App from './App.svelte'
import { mount } from 'svelte'
const app = new App({ const app = mount(App, {
target: document.querySelector('#app') target: document.querySelector('#app')
}) })

@ -1,14 +1,14 @@
<script> <script>
import { getMatches } from "@tauri-apps/plugin-cli"; import { getMatches } from '@tauri-apps/plugin-cli'
export let onMessage; export let onMessage
function cliMatches() { function cliMatches() {
getMatches().then(onMessage).catch(onMessage); getMatches().then(onMessage).catch(onMessage)
} }
</script> </script>
<p> <div>
This binary can be run from the terminal and takes the following arguments: This binary can be run from the terminal and takes the following arguments:
<code class="code-block flex flex-wrap my-2"> <code class="code-block flex flex-wrap my-2">
<pre> <pre>
@ -17,7 +17,7 @@
--verbose</pre> --verbose</pre>
</code> </code>
Additionally, it has a <code>update --background</code> subcommand. Additionally, it has a <code>update --background</code> subcommand.
</p> </div>
<br /> <br />
<div class="note"> <div class="note">
Note that the arguments are only parsed, not implemented. Note that the arguments are only parsed, not implemented.

@ -1,69 +1,69 @@
<script> <script>
import { fetch as tauriFetch } from "@tauri-apps/plugin-http"; import { fetch as tauriFetch } from '@tauri-apps/plugin-http'
import { JsonView } from "@zerodevx/svelte-json-view"; import { JsonView } from '@zerodevx/svelte-json-view'
let httpMethod = "GET"; let httpMethod = 'GET'
let httpBody = ""; let httpBody = ''
export let onMessage; export let onMessage
async function makeHttpRequest() { async function makeHttpRequest() {
let method = httpMethod || "GET"; let method = httpMethod || 'GET'
const options = { const options = {
method: method || "GET", method: method || 'GET',
headers: {}, headers: {}
}; }
let bodyType; let bodyType
if (method !== "GET") { if (method !== 'GET') {
options.body = httpBody; options.body = httpBody
if ( if (
(httpBody.startsWith("{") && httpBody.endsWith("}")) || (httpBody.startsWith('{') && httpBody.endsWith('}')) ||
(httpBody.startsWith("[") && httpBody.endsWith("]")) (httpBody.startsWith('[') && httpBody.endsWith(']'))
) { ) {
options.headers["Content-Type"] = "application/json"; options.headers['Content-Type'] = 'application/json'
bodyType = "json"; bodyType = 'json'
} else if (httpBody !== "") { } else if (httpBody !== '') {
bodyType = "text"; bodyType = 'text'
} }
} }
const response = await tauriFetch("http://localhost:3003", options); const response = await tauriFetch('http://localhost:3003', options)
const body = const body =
bodyType === "json" ? await response.json() : await response.text(); bodyType === 'json' ? await response.json() : await response.text()
onMessage({ onMessage({
url: response.url, url: response.url,
status: response.status, status: response.status,
ok: response.ok, ok: response.ok,
headers: Object.fromEntries(response.headers.entries()), headers: Object.fromEntries(response.headers.entries()),
body, body
}); })
} }
/// http form /// http form
let foo = "baz"; let foo = 'baz'
let bar = "qux"; let bar = 'qux'
let result = null; let result = null
async function doPost() { async function doPost() {
const form = new FormData(); const form = new FormData()
form.append("foo", foo); form.append('foo', foo)
form.append("bar", bar); form.append('bar', bar)
const response = await tauriFetch("http://localhost:3003/tauri", { const response = await tauriFetch('http://localhost:3003/tauri', {
method: "POST", method: 'POST',
body: form, body: form
}); })
result = { result = {
url: response.url, url: response.url,
status: response.status, status: response.status,
ok: response.ok, ok: response.ok,
headers: Object.fromEntries(response.headers.entries()), headers: Object.fromEntries(response.headers.entries()),
body: await response.text(), body: await response.text()
}; }
} }
</script> </script>
@ -82,7 +82,7 @@
placeholder="Request body" placeholder="Request body"
rows="5" rows="5"
bind:value={httpBody} bind:value={httpBody}
/> ></textarea>
<br /> <br />
<button class="btn" id="make-request"> Make request </button> <button class="btn" id="make-request"> Make request </button>
</form> </form>

@ -1,38 +1,44 @@
<script> <script>
import { scan, checkPermissions, requestPermissions, Format, cancel } from "@tauri-apps/plugin-barcode-scanner"; import {
scan,
checkPermissions,
requestPermissions,
Format,
cancel
} from '@tauri-apps/plugin-barcode-scanner'
export let onMessage; export let onMessage
let scanning = false; let scanning = false
let windowed = true; let windowed = true
let formats = [Format.QRCode]; let formats = [Format.QRCode]
const supportedFormats = [Format.QRCode, Format.EAN13]; const supportedFormats = [Format.QRCode, Format.EAN13]
async function startScan() { async function startScan() {
let permission = await checkPermissions(); let permission = await checkPermissions()
if (permission === 'prompt') { if (permission === 'prompt') {
permission = await requestPermissions(); permission = await requestPermissions()
} }
if (permission === 'granted') { if (permission === 'granted') {
scanning = true; scanning = true
scan({ windowed, formats }) scan({ windowed, formats })
.then((res) => { .then((res) => {
scanning = false; scanning = false
onMessage(res); onMessage(res)
}) })
.catch((error) => { .catch((error) => {
scanning = false; scanning = false
onMessage(error); onMessage(error)
}); })
} else { } else {
onMessage('Permission denied') onMessage('Permission denied')
} }
} }
async function cancelScan() { async function cancelScan() {
await cancel(); await cancel()
scanning = false; scanning = false
onMessage("cancelled"); onMessage('cancelled')
} }
</script> </script>
@ -59,11 +65,12 @@
<div class="barcode-scanner--area--container"> <div class="barcode-scanner--area--container">
<div class="relative"> <div class="relative">
<p>Aim your camera at a QR code</p> <p>Aim your camera at a QR code</p>
<button class="btn" type="button" on:click={cancelScan}>Cancel</button> <button class="btn" type="button" on:click={cancelScan}>Cancel</button
>
</div> </div>
<div class="square surround-cover"> <div class="square surround-cover">
<div class="barcode-scanner--area--outer surround-cover"> <div class="barcode-scanner--area--outer surround-cover">
<div class="barcode-scanner--area--inner" /> <div class="barcode-scanner--area--inner"></div>
</div> </div>
</div> </div>
</div> </div>
@ -111,7 +118,7 @@
transition: 0.3s; transition: 0.3s;
} }
.square:after { .square:after {
content: ""; content: '';
top: 0; top: 0;
display: block; display: block;
padding-bottom: 100%; padding-bottom: 100%;
@ -141,7 +148,8 @@
width: 100%; width: 100%;
margin: 1rem; margin: 1rem;
border: 2px solid #fff; border: 2px solid #fff;
box-shadow: 0px 0px 2px 1px rgb(0 0 0 / 0.5), box-shadow:
0px 0px 2px 1px rgb(0 0 0 / 0.5),
inset 0px 0px 2px 1px rgb(0 0 0 / 0.5); inset 0px 0px 2px 1px rgb(0 0 0 / 0.5);
border-radius: 1rem; border-radius: 1rem;
} }

@ -1,56 +1,56 @@
<script> <script>
import { check } from "@tauri-apps/plugin-updater"; import { check } from '@tauri-apps/plugin-updater'
import { relaunch } from "@tauri-apps/plugin-process"; import { relaunch } from '@tauri-apps/plugin-process'
export let onMessage; export let onMessage
let isChecking, isInstalling, newUpdate; let isChecking, isInstalling, newUpdate
let totalSize = 0, let totalSize = 0,
downloadedSize = 0; downloadedSize = 0
async function checkUpdate() { async function checkUpdate() {
isChecking = true; isChecking = true
try { try {
const update = await check(); const update = await check()
onMessage(`Should update: ${update.available}`); onMessage(`Should update: ${update.available}`)
onMessage(update); onMessage(update)
newUpdate = update; newUpdate = update
} catch (e) { } catch (e) {
onMessage(e); onMessage(e)
} finally { } finally {
isChecking = false; isChecking = false
} }
} }
async function install() { async function install() {
isInstalling = true; isInstalling = true
downloadedSize = 0; downloadedSize = 0
try { try {
await newUpdate.downloadAndInstall((downloadProgress) => { await newUpdate.downloadAndInstall((downloadProgress) => {
switch (downloadProgress.event) { switch (downloadProgress.event) {
case "Started": case 'Started':
totalSize = downloadProgress.data.contentLength; totalSize = downloadProgress.data.contentLength
break; break
case "Progress": case 'Progress':
downloadedSize += downloadProgress.data.chunkLength; downloadedSize += downloadProgress.data.chunkLength
break; break
case "Finished": case 'Finished':
break; break
} }
}); })
onMessage("Installation complete, restarting..."); onMessage('Installation complete, restarting...')
await new Promise((resolve) => setTimeout(resolve, 2000)); await new Promise((resolve) => setTimeout(resolve, 2000))
await relaunch(); await relaunch()
} catch (e) { } catch (e) {
console.error(e); console.error(e)
onMessage(e); onMessage(e)
} finally { } finally {
isInstalling = false; isInstalling = false
} }
} }
$: progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0; $: progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0
</script> </script>
<div class="flex children:grow children:h10"> <div class="flex children:grow children:h10">
@ -61,7 +61,7 @@
{:else} {:else}
<div class="progress"> <div class="progress">
<span>{progress}%</span> <span>{progress}%</span>
<div class="progress-bar" style="width: {progress}%" /> <div class="progress-bar" style="width: {progress}%"></div>
</div> </div>
{/if} {/if}
</div> </div>

@ -10,20 +10,20 @@
"format:check": "prettier --check ." "format:check": "prettier --check ."
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.12.0", "@eslint/js": "9.14.0",
"@rollup/plugin-node-resolve": "15.3.0", "@rollup/plugin-node-resolve": "15.3.0",
"@rollup/plugin-terser": "0.4.4", "@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "11.1.6", "@rollup/plugin-typescript": "11.1.6",
"@types/eslint__js": "8.42.3", "@types/eslint__js": "8.42.3",
"covector": "^0.12.3", "covector": "^0.12.3",
"eslint": "9.12.0", "eslint": "9.14.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-plugin-security": "3.0.1", "eslint-plugin-security": "3.0.1",
"prettier": "3.3.3", "prettier": "3.3.3",
"rollup": "4.22.4", "rollup": "4.24.4",
"tslib": "2.7.0", "tslib": "2.8.1",
"typescript": "5.6.3", "typescript": "5.6.3",
"typescript-eslint": "8.9.0" "typescript-eslint": "8.12.2"
}, },
"resolutions": { "resolutions": {
"semver": ">=7.5.2", "semver": ">=7.5.2",

@ -37,4 +37,3 @@ tauri = { workspace = true, features = ["wry"] }
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
arboard = "3" arboard = "3"
image = "0.25"

@ -3,7 +3,6 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use arboard::ImageData; use arboard::ImageData;
use image::ImageEncoder;
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
use tauri::{image::Image, plugin::PluginApi, AppHandle, Runtime}; use tauri::{image::Image, plugin::PluginApi, AppHandle, Runtime};
@ -85,16 +84,11 @@ impl<R: Runtime> Clipboard<R> {
match &self.clipboard { match &self.clipboard {
Ok(clipboard) => { Ok(clipboard) => {
let image = clipboard.lock().unwrap().get_image()?; let image = clipboard.lock().unwrap().get_image()?;
let image = Image::new_owned(
let mut buffer: Vec<u8> = Vec::new(); image.bytes.to_vec(),
image::codecs::png::PngEncoder::new(&mut buffer).write_image(
&image.bytes,
image.width as u32, image.width as u32,
image.height as u32, image.height as u32,
image::ExtendedColorType::Rgba8, );
)?;
let image = Image::new_owned(buffer, image.width as u32, image.height as u32);
Ok(image) Ok(image)
} }
Err(e) => Err(crate::Error::Clipboard(e.to_string())), Err(e) => Err(crate::Error::Clipboard(e.to_string())),

@ -15,9 +15,6 @@ pub enum Error {
Clipboard(String), Clipboard(String),
#[error(transparent)] #[error(transparent)]
Tauri(#[from] tauri::Error), Tauri(#[from] tauri::Error),
#[cfg(desktop)]
#[error("invalid image: {0}")]
Image(#[from] image::ImageError),
} }
impl Serialize for Error { impl Serialize for Error {

@ -10,11 +10,11 @@
"tauri": "tauri" "tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.0.2", "@tauri-apps/api": "2.0.3",
"@tauri-apps/plugin-deep-link": "2.0.0" "@tauri-apps/plugin-deep-link": "2.0.0"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.0.2", "@tauri-apps/cli": "2.0.4",
"typescript": "^5.2.2", "typescript": "^5.2.2",
"vite": "^5.4.7" "vite": "^5.4.7"
} }

@ -1,5 +1,16 @@
# Changelog # Changelog
## \[2.0.3]
### Dependencies
- Upgraded to `fs@2.0.3`
## \[2.0.1]
- [`2302c2db`](https://github.com/tauri-apps/plugins-workspace/commit/2302c2db1c49673e61dcbda8cdb01b2c57e9ba6f) ([#1910](https://github.com/tauri-apps/plugins-workspace/pull/1910) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Fix `ask` and `confirm` not using system button texts
- [`aee14ed4`](https://github.com/tauri-apps/plugins-workspace/commit/aee14ed4261cdedc4ed7cc2686f01f437859a5c7) ([#1892](https://github.com/tauri-apps/plugins-workspace/pull/1892) by [@nashaofu](https://github.com/tauri-apps/plugins-workspace/../../nashaofu)) Set `save` dialog mime type from the `filters` extensions on Android.
## \[2.0.1] ## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
@ -288,3 +299,5 @@
pull/371)) First v2 alpha release! pull/371)) First v2 alpha release!
lpha release! lpha release!
pull/371)) First v2 alpha release! pull/371)) First v2 alpha release!
lease!
pull/371)) First v2 alpha release!

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-dialog" name = "tauri-plugin-dialog"
version = "2.0.1" version = "2.0.3"
description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application." description = "Native system dialogs for opening and saving files along with message dialogs on your Tauri application."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@ -34,7 +34,7 @@ tauri = { workspace = true }
log = { workspace = true } log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
url = { workspace = true } url = { workspace = true }
tauri-plugin-fs = { path = "../fs", version = "2.0.1" } tauri-plugin-fs = { path = "../fs", version = "2.0.3" }
[target.'cfg(target_os = "ios")'.dependencies] [target.'cfg(target_os = "ios")'.dependencies]
tauri = { workspace = true, features = ["wry"] } tauri = { workspace = true, features = ["wry"] }

@ -1 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()??"Yes",cancelButtonLabel:i?.cancelLabel?.toString()??"No"})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()??"Ok",cancelButtonLabel:i?.cancelLabel?.toString()??"Cancel"})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})} if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,yesButtonLabel:i?.okLabel?.toString(),noButtonLabel:i?.cancelLabel?.toString()})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),cancelButtonLabel:i?.cancelLabel?.toString()})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}

@ -257,8 +257,8 @@ async function ask(
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
kind: opts?.kind, kind: opts?.kind,
okButtonLabel: opts?.okLabel?.toString() ?? 'Yes', yesButtonLabel: opts?.okLabel?.toString(),
cancelButtonLabel: opts?.cancelLabel?.toString() ?? 'No' noButtonLabel: opts?.cancelLabel?.toString()
}) })
} }
@ -287,8 +287,8 @@ async function confirm(
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
kind: opts?.kind, kind: opts?.kind,
okButtonLabel: opts?.okLabel?.toString() ?? 'Ok', okButtonLabel: opts?.okLabel?.toString(),
cancelButtonLabel: opts?.cancelLabel?.toString() ?? 'Cancel' cancelButtonLabel: opts?.cancelLabel?.toString()
}) })
} }

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-dialog", "name": "@tauri-apps/plugin-dialog",
"version": "2.0.0", "version": "2.0.1",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"

@ -10,7 +10,7 @@ use tauri_plugin_fs::FsExt;
use crate::{ use crate::{
Dialog, FileDialogBuilder, FilePath, MessageDialogButtons, MessageDialogKind, Result, CANCEL, Dialog, FileDialogBuilder, FilePath, MessageDialogButtons, MessageDialogKind, Result, CANCEL,
OK, NO, OK, YES,
}; };
#[derive(Serialize)] #[derive(Serialize)]
@ -299,8 +299,8 @@ pub(crate) async fn ask<R: Runtime>(
title: Option<String>, title: Option<String>,
message: String, message: String,
kind: Option<MessageDialogKind>, kind: Option<MessageDialogKind>,
ok_button_label: Option<String>, yes_button_label: Option<String>,
cancel_button_label: Option<String>, no_button_label: Option<String>,
) -> Result<bool> { ) -> Result<bool> {
Ok(message_dialog( Ok(message_dialog(
window, window,
@ -308,7 +308,16 @@ pub(crate) async fn ask<R: Runtime>(
title, title,
message, message,
kind, kind,
get_ok_cancel_type(ok_button_label, cancel_button_label), if let Some(yes_button_label) = yes_button_label {
MessageDialogButtons::OkCancelCustom(
yes_button_label,
no_button_label.unwrap_or(NO.to_string()),
)
} else if let Some(no_button_label) = no_button_label {
MessageDialogButtons::OkCancelCustom(YES.to_string(), no_button_label)
} else {
MessageDialogButtons::YesNo
},
)) ))
} }
@ -328,22 +337,15 @@ pub(crate) async fn confirm<R: Runtime>(
title, title,
message, message,
kind, kind,
get_ok_cancel_type(ok_button_label, cancel_button_label), if let Some(ok_button_label) = ok_button_label {
MessageDialogButtons::OkCancelCustom(
ok_button_label,
cancel_button_label.unwrap_or(CANCEL.to_string()),
)
} else if let Some(cancel_button_label) = cancel_button_label {
MessageDialogButtons::OkCancelCustom(OK.to_string(), cancel_button_label)
} else {
MessageDialogButtons::OkCancel
},
)) ))
} }
fn get_ok_cancel_type(
ok_button_label: Option<String>,
cancel_button_label: Option<String>,
) -> MessageDialogButtons {
if let Some(ok_button_label) = ok_button_label {
MessageDialogButtons::OkCancelCustom(
ok_button_label,
cancel_button_label.unwrap_or(CANCEL.to_string()),
)
} else if let Some(cancel_button_label) = cancel_button_label {
MessageDialogButtons::OkCancelCustom(OK.to_string(), cancel_button_label)
} else {
MessageDialogButtons::OkCancel
}
}

@ -112,6 +112,7 @@ impl From<MessageDialogButtons> for rfd::MessageButtons {
match value { match value {
MessageDialogButtons::Ok => Self::Ok, MessageDialogButtons::Ok => Self::Ok,
MessageDialogButtons::OkCancel => Self::OkCancel, MessageDialogButtons::OkCancel => Self::OkCancel,
MessageDialogButtons::YesNo => Self::YesNo,
MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok), MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok),
MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel), MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel),
} }

@ -43,6 +43,8 @@ use mobile::*;
pub(crate) const OK: &str = "Ok"; pub(crate) const OK: &str = "Ok";
pub(crate) const CANCEL: &str = "Cancel"; pub(crate) const CANCEL: &str = "Cancel";
pub(crate) const YES: &str = "Yes";
pub(crate) const NO: &str = "No";
macro_rules! blocking_fn { macro_rules! blocking_fn {
($self:ident, $fn:ident) => {{ ($self:ident, $fn:ident) => {{
@ -236,6 +238,7 @@ impl<R: Runtime> MessageDialogBuilder<R> {
let (ok_button_label, cancel_button_label) = match &self.buttons { let (ok_button_label, cancel_button_label) = match &self.buttons {
MessageDialogButtons::Ok => (Some(OK), None), MessageDialogButtons::Ok => (Some(OK), None),
MessageDialogButtons::OkCancel => (Some(OK), Some(CANCEL)), MessageDialogButtons::OkCancel => (Some(OK), Some(CANCEL)),
MessageDialogButtons::YesNo => (Some(YES), Some(NO)),
MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), Some(CANCEL)), MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), Some(CANCEL)),
MessageDialogButtons::OkCancelCustom(ok, cancel) => { MessageDialogButtons::OkCancelCustom(ok, cancel) => {
(Some(ok.as_str()), Some(cancel.as_str())) (Some(ok.as_str()), Some(cancel.as_str()))

@ -59,6 +59,8 @@ pub enum MessageDialogButtons {
Ok, Ok,
/// 2 buttons `Ok` and `Cancel` with OS default dialog texts /// 2 buttons `Ok` and `Cancel` with OS default dialog texts
OkCancel, OkCancel,
/// 2 buttons `Yes` and `No` with OS default dialog texts
YesNo,
/// A single `Ok` button with custom text /// A single `Ok` button with custom text
OkCustom(String), OkCustom(String),
/// 2 buttons `Ok` and `Cancel` with custom texts /// 2 buttons `Ok` and `Cancel` with custom texts

@ -1,5 +1,13 @@
# Changelog # Changelog
## \[2.0.3]
- [`14cee64c`](https://github.com/tauri-apps/plugins-workspace/commit/14cee64c82a72655ae6a4ac0892736a2959dbda5) ([#1958](https://github.com/tauri-apps/plugins-workspace/pull/1958) by [@bWanShiTong](https://github.com/tauri-apps/plugins-workspace/../../bWanShiTong)) Fix compilation on targets with pointer width of `16` or `32`
## \[2.0.1]
- [`ae802456`](https://github.com/tauri-apps/plugins-workspace/commit/ae8024565f074f313084777c8b10d1b5e3bbe220) ([#1950](https://github.com/tauri-apps/plugins-workspace/pull/1950) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Improve performance of the `FileHandle.read` and `writeTextFile` APIs.
## \[2.0.1] ## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-fs" name = "tauri-plugin-fs"
version = "2.0.1" version = "2.0.3"
description = "Access the file system." description = "Access the file system."
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }
@ -35,8 +35,12 @@ url = { workspace = true }
anyhow = "1" anyhow = "1"
uuid = { version = "1", features = ["v4"] } uuid = { version = "1", features = ["v4"] }
glob = "0.3" glob = "0.3"
notify = { version = "6", optional = true, features = ["serde"] } # TODO: Remove `serialization-compat-6` in v3
notify-debouncer-full = { version = "0.3", optional = true } notify = { version = "7", optional = true, features = [
"serde",
"serialization-compat-6",
] }
notify-debouncer-full = { version = "0.4", optional = true }
dunce = { workspace = true } dunce = { workspace = true }
percent-encoding = "2" percent-encoding = "2"

File diff suppressed because one or more lines are too long

@ -243,6 +243,25 @@ function parseFileInfo(r: UnparsedFileInfo): FileInfo {
} }
} }
// https://mstn.github.io/2018/06/08/fixed-size-arrays-in-typescript/
type FixedSizeArray<T, N extends number> = ReadonlyArray<T> & {
length: N
}
// https://gist.github.com/zapthedingbat/38ebfbedd98396624e5b5f2ff462611d
/** Converts a big-endian eight byte array to number */
function fromBytes(buffer: FixedSizeArray<number, 8>): number {
const bytes = new Uint8ClampedArray(buffer)
const size = bytes.byteLength
let x = 0
for (let i = 0; i < size; i++) {
const byte = bytes[i]
x *= 0x100
x += byte
}
return x
}
/** /**
* The Tauri abstraction for reading and writing files. * The Tauri abstraction for reading and writing files.
* *
@ -285,12 +304,20 @@ class FileHandle extends Resource {
return 0 return 0
} }
const [data, nread] = await invoke<[number[], number]>('plugin:fs|read', { const data = await invoke<ArrayBuffer | number[]>('plugin:fs|read', {
rid: this.rid, rid: this.rid,
len: buffer.byteLength len: buffer.byteLength
}) })
buffer.set(data) // Rust side will never return an empty array for this command and
// ensure there is at least 8 elements there.
//
// This is an optimization to include the number of read bytes (as bigendian bytes)
// at the end of returned array to avoid serialization overhead of separate values.
const nread = fromBytes(data.slice(-8) as FixedSizeArray<number, 8>)
const bytes = data instanceof ArrayBuffer ? new Uint8Array(data) : data
buffer.set(bytes.slice(0, bytes.length - 8))
return nread === 0 ? null : nread return nread === 0 ? null : nread
} }
@ -1041,10 +1068,13 @@ async function writeTextFile(
throw new TypeError('Must be a file URL.') throw new TypeError('Must be a file URL.')
} }
await invoke('plugin:fs|write_text_file', { const encoder = new TextEncoder()
path: path instanceof URL ? path.toString() : path,
data, await invoke('plugin:fs|write_text_file', encoder.encode(data), {
options headers: {
path: encodeURIComponent(path instanceof URL ? path.toString() : path),
options: JSON.stringify(options)
}
}) })
} }

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-fs", "name": "@tauri-apps/plugin-fs",
"version": "2.0.0", "version": "2.0.1",
"description": "Access the file system.", "description": "Access the file system.",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [

@ -24,6 +24,7 @@ This default permission set prevents access to critical components
of the Tauri application by default. of the Tauri application by default.
On Windows the webview data folder access is denied. On Windows the webview data folder access is denied.
#### Included permissions within this default permission set:
- `create-app-specific-dirs` - `create-app-specific-dirs`

@ -26,6 +26,7 @@ This default permission set prevents access to critical components
of the Tauri application by default. of the Tauri application by default.
On Windows the webview data folder access is denied. On Windows the webview data folder access is denied.
#### Included permissions within this default permission set:
""" """
permissions = [ permissions = [
"create-app-specific-dirs", "create-app-specific-dirs",

@ -1665,7 +1665,7 @@
"const": "create-app-specific-dirs" "const": "create-app-specific-dirs"
}, },
{ {
"description": "This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n\n", "description": "This set of permissions describes the what kind of\nfile system access the `fs` plugin has enabled or denied by default.\n\n#### Granted Permissions\n\nThis default permission set enables read access to the\napplication specific directories (AppConfig, AppData, AppLocalData, AppCache,\nAppLog) and all files and sub directories created in it.\nThe location of these directories depends on the operating system,\nwhere the application is run.\n\nIn general these directories need to be manually created\nby the application at runtime, before accessing files or folders\nin it is possible.\n\nTherefore, it is also allowed to create all of these folders via\nthe `mkdir` command.\n\n#### Denied Permissions\n\nThis default permission set prevents access to critical components\nof the Tauri application by default.\nOn Windows the webview data folder access is denied.\n\n#### Included permissions within this default permission set:\n",
"type": "string", "type": "string",
"const": "default" "const": "default"
}, },

@ -9,7 +9,7 @@ use tauri::{
ipc::{CommandScope, GlobalScope}, ipc::{CommandScope, GlobalScope},
path::BaseDirectory, path::BaseDirectory,
utils::config::FsScope, utils::config::FsScope,
AppHandle, Manager, Resource, ResourceId, Runtime, Webview, Manager, Resource, ResourceId, Runtime, Webview,
}; };
use std::{ use std::{
@ -301,13 +301,36 @@ pub async fn read_dir<R: Runtime>(
pub async fn read<R: Runtime>( pub async fn read<R: Runtime>(
webview: Webview<R>, webview: Webview<R>,
rid: ResourceId, rid: ResourceId,
len: u32, len: usize,
) -> CommandResult<(Vec<u8>, usize)> { ) -> CommandResult<tauri::ipc::Response> {
let mut data = vec![0; len as usize]; let mut data = vec![0; len];
let file = webview.resources_table().get::<StdFileResource>(rid)?; let file = webview.resources_table().get::<StdFileResource>(rid)?;
let nread = StdFileResource::with_lock(&file, |mut file| file.read(&mut data)) let nread = StdFileResource::with_lock(&file, |mut file| file.read(&mut data))
.map_err(|e| format!("faied to read bytes from file with error: {e}"))?; .map_err(|e| format!("faied to read bytes from file with error: {e}"))?;
Ok((data, nread))
// This is an optimization to include the number of read bytes (as bigendian bytes)
// at the end of returned vector so we can use `tauri::ipc::Response`
// and avoid serialization overhead of separate values.
#[cfg(target_pointer_width = "16")]
let nread = {
let nread = nread.to_be_bytes();
let mut out = [0; 8];
out[6..].copy_from_slice(&nread);
out
};
#[cfg(target_pointer_width = "32")]
let nread = {
let nread = nread.to_be_bytes();
let mut out = [0; 8];
out[4..].copy_from_slice(&nread);
out
};
#[cfg(target_pointer_width = "64")]
let nread = nread.to_be_bytes();
data.extend(nread);
Ok(tauri::ipc::Response::new(data))
} }
#[tauri::command] #[tauri::command]
@ -783,10 +806,34 @@ fn write_file_inner<R: Runtime>(
webview: Webview<R>, webview: Webview<R>,
global_scope: &GlobalScope<Entry>, global_scope: &GlobalScope<Entry>,
command_scope: &CommandScope<Entry>, command_scope: &CommandScope<Entry>,
path: SafeFilePath, request: tauri::ipc::Request<'_>,
data: &[u8],
options: Option<WriteFileOptions>,
) -> CommandResult<()> { ) -> CommandResult<()> {
let data = match request.body() {
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
data.iter()
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
.collect(),
),
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
};
let path = request
.headers()
.get("path")
.ok_or_else(|| anyhow::anyhow!("missing file path").into())
.and_then(|p| {
percent_encoding::percent_decode(p.as_ref())
.decode_utf8()
.map_err(|_| anyhow::anyhow!("path is not a valid UTF-8").into())
})
.and_then(|p| SafeFilePath::from_str(&p).map_err(CommandError::from))?;
let options: Option<WriteFileOptions> = request
.headers()
.get("options")
.and_then(|p| p.to_str().ok())
.and_then(|opts| serde_json::from_str(opts).ok());
let (mut file, path) = resolve_file( let (mut file, path) = resolve_file(
&webview, &webview,
global_scope, global_scope,
@ -823,7 +870,7 @@ fn write_file_inner<R: Runtime>(
}, },
)?; )?;
file.write_all(data) file.write_all(&data)
.map_err(|e| { .map_err(|e| {
format!( format!(
"failed to write bytes to file at path: {} with error: {e}", "failed to write bytes to file at path: {} with error: {e}",
@ -840,52 +887,18 @@ pub async fn write_file<R: Runtime>(
command_scope: CommandScope<Entry>, command_scope: CommandScope<Entry>,
request: tauri::ipc::Request<'_>, request: tauri::ipc::Request<'_>,
) -> CommandResult<()> { ) -> CommandResult<()> {
let data = match request.body() { write_file_inner(webview, &global_scope, &command_scope, request)
tauri::ipc::InvokeBody::Raw(data) => Cow::Borrowed(data),
tauri::ipc::InvokeBody::Json(serde_json::Value::Array(data)) => Cow::Owned(
data.iter()
.flat_map(|v| v.as_number().and_then(|v| v.as_u64().map(|v| v as u8)))
.collect(),
),
_ => return Err(anyhow::anyhow!("unexpected invoke body").into()),
};
let path = request
.headers()
.get("path")
.ok_or_else(|| anyhow::anyhow!("missing file path").into())
.and_then(|p| {
percent_encoding::percent_decode(p.as_ref())
.decode_utf8()
.map_err(|_| anyhow::anyhow!("path is not a valid UTF-8").into())
})
.and_then(|p| SafeFilePath::from_str(&p).map_err(CommandError::from))?;
let options = request
.headers()
.get("options")
.and_then(|p| p.to_str().ok())
.and_then(|opts| serde_json::from_str(opts).ok());
write_file_inner(webview, &global_scope, &command_scope, path, &data, options)
} }
// TODO, in v3, remove this command and rely on `write_file` command only
#[tauri::command] #[tauri::command]
pub async fn write_text_file<R: Runtime>( pub async fn write_text_file<R: Runtime>(
#[allow(unused)] app: AppHandle<R>, webview: Webview<R>,
#[allow(unused)] webview: Webview<R>, global_scope: GlobalScope<Entry>,
#[allow(unused)] global_scope: GlobalScope<Entry>, command_scope: CommandScope<Entry>,
#[allow(unused)] command_scope: CommandScope<Entry>, request: tauri::ipc::Request<'_>,
path: SafeFilePath,
data: String,
#[allow(unused)] options: Option<WriteFileOptions>,
) -> CommandResult<()> { ) -> CommandResult<()> {
write_file_inner( write_file_inner(webview, &global_scope, &command_scope, request)
webview,
&global_scope,
&command_scope,
path,
data.as_bytes(),
options,
)
} }
#[tauri::command] #[tauri::command]

@ -3,7 +3,7 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher}; use notify::{Config, Event, RecommendedWatcher, RecursiveMode, Watcher};
use notify_debouncer_full::{new_debouncer, DebounceEventResult, Debouncer, FileIdMap}; use notify_debouncer_full::{new_debouncer, DebounceEventResult, Debouncer, RecommendedCache};
use serde::Deserialize; use serde::Deserialize;
use tauri::{ use tauri::{
ipc::{Channel, CommandScope, GlobalScope}, ipc::{Channel, CommandScope, GlobalScope},
@ -47,7 +47,7 @@ impl WatcherResource {
impl Resource for WatcherResource {} impl Resource for WatcherResource {}
enum WatcherKind { enum WatcherKind {
Debouncer(Debouncer<RecommendedWatcher, FileIdMap>), Debouncer(Debouncer<RecommendedWatcher, RecommendedCache>),
Watcher(RecommendedWatcher), Watcher(RecommendedWatcher),
} }
@ -111,8 +111,7 @@ pub async fn watch<R: Runtime>(
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?; let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
for path in &resolved_paths { for path in &resolved_paths {
debouncer.watcher().watch(path.as_ref(), recursive_mode)?; debouncer.watch(path, recursive_mode)?;
debouncer.cache().add_root(path, recursive_mode);
} }
watch_debounced(on_event, rx); watch_debounced(on_event, rx);
WatcherKind::Debouncer(debouncer) WatcherKind::Debouncer(debouncer)
@ -120,7 +119,7 @@ pub async fn watch<R: Runtime>(
let (tx, rx) = channel(); let (tx, rx) = channel();
let mut watcher = RecommendedWatcher::new(tx, Config::default())?; let mut watcher = RecommendedWatcher::new(tx, Config::default())?;
for path in &resolved_paths { for path in &resolved_paths {
watcher.watch(path.as_ref(), recursive_mode)?; watcher.watch(path, recursive_mode)?;
} }
watch_raw(on_event, rx); watch_raw(on_event, rx);
WatcherKind::Watcher(watcher) WatcherKind::Watcher(watcher)
@ -140,14 +139,14 @@ pub async fn unwatch<R: Runtime>(webview: Webview<R>, rid: ResourceId) -> Comman
match &mut watcher.kind { match &mut watcher.kind {
WatcherKind::Debouncer(ref mut debouncer) => { WatcherKind::Debouncer(ref mut debouncer) => {
for path in &watcher.paths { for path in &watcher.paths {
debouncer.watcher().unwatch(path.as_ref()).map_err(|e| { debouncer.unwatch(path).map_err(|e| {
format!("failed to unwatch path: {} with error: {e}", path.display()) format!("failed to unwatch path: {} with error: {e}", path.display())
})?; })?;
} }
} }
WatcherKind::Watcher(ref mut w) => { WatcherKind::Watcher(ref mut w) => {
for path in &watcher.paths { for path in &watcher.paths {
w.unwatch(path.as_ref()).map_err(|e| { w.unwatch(path).map_err(|e| {
format!("failed to unwatch path: {} with error: {e}", path.display()) format!("failed to unwatch path: {} with error: {e}", path.display())
})?; })?;
} }

@ -1,5 +1,16 @@
# Changelog # Changelog
## \[2.0.3]
### Dependencies
- Upgraded to `fs@2.0.3`
## \[2.0.1]
- [`cfd48b3b`](https://github.com/tauri-apps/plugins-workspace/commit/cfd48b3b2ec0fccfc162197518694ed59ceda22c) ([#1941](https://github.com/tauri-apps/plugins-workspace/pull/1941) by [@Nipsuli](https://github.com/tauri-apps/plugins-workspace/../../Nipsuli)) Allow skipping sending `Origin` header in HTTP requests by setting `Origin` header to an empty string when calling `fetch`.
- [`9b2840db`](https://github.com/tauri-apps/plugins-workspace/commit/9b2840db9464cf08db75806270e4441f0af81e5d) ([#1884](https://github.com/tauri-apps/plugins-workspace/pull/1884) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Retain headers order.
## \[2.0.1] ## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
@ -286,3 +297,6 @@
ha release! ha release!
! !
371\)) First v2 alpha release! 371\)) First v2 alpha release!
lease!
!
371\)) First v2 alpha release!

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-http" name = "tauri-plugin-http"
version = "2.0.1" version = "2.0.3"
description = "Access an HTTP client written in Rust." description = "Access an HTTP client written in Rust."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }
@ -34,7 +34,7 @@ serde_json = { workspace = true }
tauri = { workspace = true } tauri = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
tokio = { version = "1", features = ["sync", "macros"] } tokio = { version = "1", features = ["sync", "macros"] }
tauri-plugin-fs = { path = "../fs", version = "2.0.1" } tauri-plugin-fs = { path = "../fs", version = "2.0.3" }
urlpattern = "0.3" urlpattern = "0.3"
regex = "1" regex = "1"
http = "1" http = "1"

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-http", "name": "@tauri-apps/plugin-http",
"version": "2.0.0", "version": "2.0.1",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"

@ -191,6 +191,11 @@ pub async fn fetch<R: Runtime>(
let name = HeaderName::from_str(&h)?; let name = HeaderName::from_str(&h)?;
#[cfg(not(feature = "unsafe-headers"))] #[cfg(not(feature = "unsafe-headers"))]
if is_unsafe_header(&name) { if is_unsafe_header(&name) {
#[cfg(debug_assertions)]
{
eprintln!("[\x1b[33mWARNING\x1b[0m] Skipping {name} header as it is a forbidden header per fetch spec https://fetch.spec.whatwg.org/#terminology-headers");
eprintln!("[\x1b[33mWARNING\x1b[0m] if keeping the header is a desired behavior, you can enable `unsafe-headers` feature flag in your Cargo.toml");
}
continue; continue;
} }

@ -31,7 +31,7 @@ serde_repr = "0.1"
byte-unit = "5" byte-unit = "5"
log = { workspace = true, features = ["kv_unstable"] } log = { workspace = true, features = ["kv_unstable"] }
time = { version = "0.3", features = ["formatting", "local-offset"] } time = { version = "0.3", features = ["formatting", "local-offset"] }
fern = "0.6" fern = "0.7"
thiserror = "1" thiserror = "1"
[target."cfg(target_os = \"android\")".dependencies] [target."cfg(target_os = \"android\")".dependencies]

@ -1 +1 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_NOTIFICATION__=function(i){"use strict";function t(i,t,n,e){if("a"===n&&!e)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?i!==t||!e:!t.has(i))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?e:"a"===n?e.call(i):e?e.value:t.get(i)}function n(i,t,n,e,o){if("function"==typeof t?i!==t||!o:!t.has(i))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(i,n),n}var e,o,a,r,c,s;"function"==typeof SuppressedError&&SuppressedError;class l{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,e.set(this,(()=>{})),o.set(this,0),a.set(this,{}),this.id=function(i,t=!1){return window.__TAURI_INTERNALS__.transformCallback(i,t)}((({message:i,id:r})=>{if(r===t(this,o,"f")){n(this,o,r+1),t(this,e,"f").call(this,i);const c=Object.keys(t(this,a,"f"));if(c.length>0){let i=r+1;for(const n of c.sort()){if(parseInt(n)!==i)break;{const o=t(this,a,"f")[n];delete t(this,a,"f")[n],t(this,e,"f").call(this,o),i+=1}}n(this,o,i)}}else t(this,a,"f")[r.toString()]=i}))}set onmessage(i){n(this,e,i)}get onmessage(){return t(this,e,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}e=new WeakMap,o=new WeakMap,a=new WeakMap;class u{constructor(i,t,n){this.plugin=i,this.event=t,this.channelId=n}async unregister(){return d(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function f(i,t,n){const e=new l;return e.onmessage=n,d(`plugin:${i}|register_listener`,{event:t,handler:e}).then((()=>new u(i,t,e.id)))}async function d(i,t={},n){return window.__TAURI_INTERNALS__.invoke(i,t,n)}i.ScheduleEvery=void 0,(r=i.ScheduleEvery||(i.ScheduleEvery={})).Year="year",r.Month="month",r.TwoWeeks="twoWeeks",r.Week="week",r.Day="day",r.Hour="hour",r.Minute="minute",r.Second="second";return i.Importance=void 0,(c=i.Importance||(i.Importance={}))[c.None=0]="None",c[c.Min=1]="Min",c[c.Low=2]="Low",c[c.Default=3]="Default",c[c.High=4]="High",i.Visibility=void 0,(s=i.Visibility||(i.Visibility={}))[s.Secret=-1]="Secret",s[s.Private=0]="Private",s[s.Public=1]="Public",i.Schedule=class{static at(i,t=!1,n=!1){return{at:{date:i,repeating:t,allowWhileIdle:n},interval:void 0,every:void 0}}static interval(i,t=!1){return{at:void 0,interval:{interval:i,allowWhileIdle:t},every:void 0}}static every(i,t,n=!1){return{at:void 0,interval:void 0,every:{interval:i,count:t,allowWhileIdle:n}}}},i.active=async function(){return await d("plugin:notification|get_active")},i.cancel=async function(i){await d("plugin:notification|cancel",{notifications:i})},i.cancelAll=async function(){await d("plugin:notification|cancel")},i.channels=async function(){return await d("plugin:notification|listChannels")},i.createChannel=async function(i){await d("plugin:notification|create_channel",{...i})},i.isPermissionGranted=async function(){return"default"!==window.Notification.permission?await Promise.resolve("granted"===window.Notification.permission):await d("plugin:notification|is_permission_granted")},i.onAction=async function(i){return await f("notification","actionPerformed",i)},i.onNotificationReceived=async function(i){return await f("notification","notification",i)},i.pending=async function(){return await d("plugin:notification|get_pending")},i.registerActionTypes=async function(i){await d("plugin:notification|register_action_types",{types:i})},i.removeActive=async function(i){await d("plugin:notification|remove_active",{notifications:i})},i.removeAllActive=async function(){await d("plugin:notification|remove_active")},i.removeChannel=async function(i){await d("plugin:notification|delete_channel",{id:i})},i.requestPermission=async function(){return await window.Notification.requestPermission()},i.sendNotification=function(i){"string"==typeof i?new window.Notification(i):new window.Notification(i.title,i)},i}({});Object.defineProperty(window.__TAURI__,"notification",{value:__TAURI_PLUGIN_NOTIFICATION__})} if("__TAURI__"in window){var __TAURI_PLUGIN_NOTIFICATION__=function(i){"use strict";function t(i,t,n,e){if("a"===n&&!e)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?i!==t||!e:!t.has(i))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===n?e:"a"===n?e.call(i):e?e.value:t.get(i)}function n(i,t,n,e,o){if("function"==typeof t?i!==t||!o:!t.has(i))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(i,n),n}var e,o,a,r,c,s;"function"==typeof SuppressedError&&SuppressedError;class l{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,e.set(this,(()=>{})),o.set(this,0),a.set(this,{}),this.id=function(i,t=!1){return window.__TAURI_INTERNALS__.transformCallback(i,t)}((({message:i,id:r})=>{if(r===t(this,o,"f")){n(this,o,r+1),t(this,e,"f").call(this,i);const c=Object.keys(t(this,a,"f"));if(c.length>0){let i=r+1;for(const n of c.sort()){if(parseInt(n)!==i)break;{const o=t(this,a,"f")[n];delete t(this,a,"f")[n],t(this,e,"f").call(this,o),i+=1}}n(this,o,i)}}else t(this,a,"f")[r.toString()]=i}))}set onmessage(i){n(this,e,i)}get onmessage(){return t(this,e,"f")}toJSON(){return`__CHANNEL__:${this.id}`}}e=new WeakMap,o=new WeakMap,a=new WeakMap;class u{constructor(i,t,n){this.plugin=i,this.event=t,this.channelId=n}async unregister(){return d(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function f(i,t,n){const e=new l;return e.onmessage=n,d(`plugin:${i}|registerListener`,{event:t,handler:e}).then((()=>new u(i,t,e.id)))}async function d(i,t={},n){return window.__TAURI_INTERNALS__.invoke(i,t,n)}i.ScheduleEvery=void 0,(r=i.ScheduleEvery||(i.ScheduleEvery={})).Year="year",r.Month="month",r.TwoWeeks="twoWeeks",r.Week="week",r.Day="day",r.Hour="hour",r.Minute="minute",r.Second="second";return i.Importance=void 0,(c=i.Importance||(i.Importance={}))[c.None=0]="None",c[c.Min=1]="Min",c[c.Low=2]="Low",c[c.Default=3]="Default",c[c.High=4]="High",i.Visibility=void 0,(s=i.Visibility||(i.Visibility={}))[s.Secret=-1]="Secret",s[s.Private=0]="Private",s[s.Public=1]="Public",i.Schedule=class{static at(i,t=!1,n=!1){return{at:{date:i,repeating:t,allowWhileIdle:n},interval:void 0,every:void 0}}static interval(i,t=!1){return{at:void 0,interval:{interval:i,allowWhileIdle:t},every:void 0}}static every(i,t,n=!1){return{at:void 0,interval:void 0,every:{interval:i,count:t,allowWhileIdle:n}}}},i.active=async function(){return await d("plugin:notification|get_active")},i.cancel=async function(i){await d("plugin:notification|cancel",{notifications:i})},i.cancelAll=async function(){await d("plugin:notification|cancel")},i.channels=async function(){return await d("plugin:notification|listChannels")},i.createChannel=async function(i){await d("plugin:notification|create_channel",{...i})},i.isPermissionGranted=async function(){return"default"!==window.Notification.permission?await Promise.resolve("granted"===window.Notification.permission):await d("plugin:notification|is_permission_granted")},i.onAction=async function(i){return await f("notification","actionPerformed",i)},i.onNotificationReceived=async function(i){return await f("notification","notification",i)},i.pending=async function(){return await d("plugin:notification|get_pending")},i.registerActionTypes=async function(i){await d("plugin:notification|register_action_types",{types:i})},i.removeActive=async function(i){await d("plugin:notification|remove_active",{notifications:i})},i.removeAllActive=async function(){await d("plugin:notification|remove_active")},i.removeChannel=async function(i){await d("plugin:notification|delete_channel",{id:i})},i.requestPermission=async function(){return await window.Notification.requestPermission()},i.sendNotification=function(i){"string"==typeof i?new window.Notification(i):new window.Notification(i.title,i)},i}({});Object.defineProperty(window.__TAURI__,"notification",{value:__TAURI_PLUGIN_NOTIFICATION__})}

@ -1,5 +1,17 @@
# Changelog # Changelog
## \[2.0.3]
### Dependencies
- Upgraded to `fs@2.0.3`
## \[2.0.2]
### Dependencies
- Upgraded to `fs@2.0.2`
## \[2.0.1] ## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-persisted-scope" name = "tauri-plugin-persisted-scope"
version = "2.0.1" version = "2.0.3"
description = "Save filesystem and asset scopes and restore them when the app is reopened." description = "Save filesystem and asset scopes and restore them when the app is reopened."
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }
@ -27,7 +27,7 @@ log = { workspace = true }
thiserror = { workspace = true } thiserror = { workspace = true }
aho-corasick = "1" aho-corasick = "1"
bincode = "1" bincode = "1"
tauri-plugin-fs = { path = "../fs", version = "2.0.1" } tauri-plugin-fs = { path = "../fs", version = "2.0.3" }
[features] [features]
protocol-asset = ["tauri/protocol-asset"] protocol-asset = ["tauri/protocol-asset"]

@ -2,6 +2,10 @@
## \[2.0.1] ## \[2.0.1]
- [`3c1f3874`](https://github.com/tauri-apps/plugins-workspace/commit/3c1f3874f4c828637b3aa983cba13c77427faf58) ([#1911](https://github.com/tauri-apps/plugins-workspace/pull/1911) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Added missing permission for `handleIconState` and fixed its event processing logic.
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0] ## \[2.0.0]

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-positioner" name = "tauri-plugin-positioner"
version = "2.0.1" version = "2.0.2"
description = "Position your windows at well-known locations." description = "Position your windows at well-known locations."
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-positioner", "name": "@tauri-apps/plugin-positioner",
"version": "2.0.0", "version": "2.0.1",
"description": "Position your windows at well-known locations.", "description": "Position your windows at well-known locations.",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [

@ -2,6 +2,10 @@
## \[2.0.1] ## \[2.0.1]
- [`51ddf6a7`](https://github.com/tauri-apps/plugins-workspace/commit/51ddf6a71544acfb261ffc9393dab1342da0a219) ([#1881](https://github.com/tauri-apps/plugins-workspace/pull/1881) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) On Windows, Fix `open` JS API hanging and freezing the app.
## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
## \[2.0.0] ## \[2.0.0]

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-shell" name = "tauri-plugin-shell"
version = "2.0.1" version = "2.0.2"
description = "Access the system shell. Allows you to spawn child processes and manage files and URLs using their default application." description = "Access the system shell. Allows you to spawn child processes and manage files and URLs using their default application."
edition = { workspace = true } edition = { workspace = true }
authors = { workspace = true } authors = { workspace = true }

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-shell", "name": "@tauri-apps/plugin-shell",
"version": "2.0.0", "version": "2.0.1",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [
"Tauri Programme within The Commons Conservancy" "Tauri Programme within The Commons Conservancy"

@ -9,6 +9,6 @@
"author": "", "author": "",
"license": "MIT", "license": "MIT",
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.0.2" "@tauri-apps/cli": "2.0.4"
} }
} }

@ -129,12 +129,12 @@ export default class Database {
* ```ts * ```ts
* // for sqlite & postgres * // for sqlite & postgres
* const result = await db.select( * const result = await db.select(
* "SELECT * from todos WHERE id = $1", id * "SELECT * from todos WHERE id = $1", [ id ]
* ); * );
* *
* // for mysql * // for mysql
* const result = await db.select( * const result = await db.select(
* "SELECT * from todos WHERE id = ?", id * "SELECT * from todos WHERE id = ?", [ id ]
* ); * );
* ``` * ```
*/ */

@ -23,7 +23,7 @@ pub(crate) async fn load<R: Runtime>(
pool.migrate(&migrator).await?; pool.migrate(&migrator).await?;
} }
db_instances.0.lock().await.insert(db.clone(), pool); db_instances.0.write().await.insert(db.clone(), pool);
Ok(db) Ok(db)
} }
@ -36,7 +36,7 @@ pub(crate) async fn close(
db_instances: State<'_, DbInstances>, db_instances: State<'_, DbInstances>,
db: Option<String>, db: Option<String>,
) -> Result<bool, crate::Error> { ) -> Result<bool, crate::Error> {
let mut instances = db_instances.0.lock().await; let instances = db_instances.0.read().await;
let pools = if let Some(db) = db { let pools = if let Some(db) = db {
vec![db] vec![db]
@ -45,9 +45,7 @@ pub(crate) async fn close(
}; };
for pool in pools { for pool in pools {
let db = instances let db = instances.get(&pool).ok_or(Error::DatabaseNotLoaded(pool))?;
.get_mut(&pool)
.ok_or(Error::DatabaseNotLoaded(pool))?;
db.close().await; db.close().await;
} }
@ -62,9 +60,9 @@ pub(crate) async fn execute(
query: String, query: String,
values: Vec<JsonValue>, values: Vec<JsonValue>,
) -> Result<(u64, LastInsertId), crate::Error> { ) -> Result<(u64, LastInsertId), crate::Error> {
let mut instances = db_instances.0.lock().await; let instances = db_instances.0.read().await;
let db = instances.get_mut(&db).ok_or(Error::DatabaseNotLoaded(db))?; let db = instances.get(&db).ok_or(Error::DatabaseNotLoaded(db))?;
db.execute(query, values).await db.execute(query, values).await
} }
@ -75,8 +73,8 @@ pub(crate) async fn select(
query: String, query: String,
values: Vec<JsonValue>, values: Vec<JsonValue>,
) -> Result<Vec<IndexMap<String, JsonValue>>, crate::Error> { ) -> Result<Vec<IndexMap<String, JsonValue>>, crate::Error> {
let mut instances = db_instances.0.lock().await; let instances = db_instances.0.read().await;
let db = instances.get_mut(&db).ok_or(Error::DatabaseNotLoaded(db))?; let db = instances.get(&db).ok_or(Error::DatabaseNotLoaded(db))?;
db.select(query, values).await db.select(query, values).await
} }

@ -29,12 +29,12 @@ use tauri::{
plugin::{Builder as PluginBuilder, TauriPlugin}, plugin::{Builder as PluginBuilder, TauriPlugin},
Manager, RunEvent, Runtime, Manager, RunEvent, Runtime,
}; };
use tokio::sync::Mutex; use tokio::sync::{Mutex, RwLock};
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Default)] #[derive(Default)]
pub struct DbInstances(pub Mutex<HashMap<String, DbPool>>); pub struct DbInstances(pub RwLock<HashMap<String, DbPool>>);
#[derive(Serialize)] #[derive(Serialize)]
#[serde(untagged)] #[serde(untagged)]
@ -140,7 +140,7 @@ impl Builder {
tauri::async_runtime::block_on(async move { tauri::async_runtime::block_on(async move {
let instances = DbInstances::default(); let instances = DbInstances::default();
let mut lock = instances.0.lock().await; let mut lock = instances.0.write().await;
for db in config.preload { for db in config.preload {
let pool = DbPool::connect(&db, app).await?; let pool = DbPool::connect(&db, app).await?;
@ -168,7 +168,7 @@ impl Builder {
if let RunEvent::Exit = event { if let RunEvent::Exit = event {
tauri::async_runtime::block_on(async move { tauri::async_runtime::block_on(async move {
let instances = &*app.state::<DbInstances>(); let instances = &*app.state::<DbInstances>();
let instances = instances.0.lock().await; let instances = instances.0.read().await;
for value in instances.values() { for value in instances.values() {
value.close().await; value.close().await;
} }

@ -1,5 +1,13 @@
# Changelog # Changelog
## \[2.1.0]
### feat
- [`8c67d44a`](https://github.com/tauri-apps/plugins-workspace/commit/8c67d44aef60b1427019538d8420787ef35bd3d5) ([#1860](https://github.com/tauri-apps/plugins-workspace/pull/1860) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) - Add `getStore`
- Add an option to use pre-stored (de)serialize functions (registered on rust)
- Add `LazyStore`
## \[2.0.1] ## \[2.0.1]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7. - [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
@ -125,3 +133,11 @@
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release! com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
plugins-workspace/pull/371)) First v2 alpha release! plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release! com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
eb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ps://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!

@ -1,6 +1,6 @@
[package] [package]
name = "tauri-plugin-store" name = "tauri-plugin-store"
version = "2.0.1" version = "2.1.0"
description = "Simple, persistent key-value store." description = "Simple, persistent key-value store."
authors = { workspace = true } authors = { workspace = true }
license = { workspace = true } license = { workspace = true }

@ -8,7 +8,7 @@
"tauri": "tauri" "tauri": "tauri"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.0.2", "@tauri-apps/cli": "2.0.4",
"vite": "^5.0.12", "vite": "^5.0.12",
"typescript": "^5.4.7" "typescript": "^5.4.7"
} }

@ -1,6 +1,6 @@
{ {
"name": "@tauri-apps/plugin-store", "name": "@tauri-apps/plugin-store",
"version": "2.0.0", "version": "2.1.0",
"description": "Simple, persistent key-value store.", "description": "Simple, persistent key-value store.",
"license": "MIT OR Apache-2.0", "license": "MIT OR Apache-2.0",
"authors": [ "authors": [

@ -9,7 +9,7 @@
"preview": "vite preview" "preview": "vite preview"
}, },
"devDependencies": { "devDependencies": {
"@tauri-apps/cli": "2.0.2", "@tauri-apps/cli": "2.0.4",
"typescript": "^5.3.3", "typescript": "^5.3.3",
"vite": "^5.4.7" "vite": "^5.4.7"
}, },

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save