mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-18 14:40:07 +02:00
Compare commits
96 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 926190d5d6 | |||
| 5347de8db9 | |||
| d3183aa99d | |||
| 1e9e496b06 | |||
| 1bb1ced538 | |||
| 68eb74353b | |||
| 95e8f909b1 | |||
| 8882dea3b9 | |||
| b40a02c525 | |||
| a1b3fa27f1 | |||
| e54cfcb261 | |||
| 22ba197b80 | |||
| 77520a3587 | |||
| dbc5fe120a | |||
| faefcc9fd8 | |||
| ac60d589ec | |||
| cb38f54f4a | |||
| d37bbdef8d | |||
| 3a750c7300 | |||
| 5c9cf52e75 | |||
| 02df0421d6 | |||
| f7f5bbf259 | |||
| 561cf39f64 | |||
| 024815018f | |||
| e90cd9fab1 | |||
| 1b86af8e26 | |||
| 1dba334f00 | |||
| 54e7864507 | |||
| 45c7848714 | |||
| 393e956728 | |||
| 1a9846599b | |||
| 71f95c9f05 | |||
| 8b3cd9e827 | |||
| 39c022eea2 | |||
| 7527a3465a | |||
| abca2ebc0d | |||
| ddcfad46f9 | |||
| fbd4d28920 | |||
| 0af367f7d4 | |||
| 1ab5f15763 | |||
| c10d5bfb54 | |||
| f6838d507f | |||
| 5b3a1aaf73 | |||
| 3276d65801 | |||
| e0900f0451 | |||
| 4d38066ef9 | |||
| 3b37ce1508 | |||
| 6f881293fc | |||
| 9229f991fe | |||
| b3bf74212e | |||
| c5da9d2579 | |||
| 7a5495963b | |||
| 7d3869ced8 | |||
| fa8c544479 | |||
| 14660b6230 | |||
| 6b4c391738 | |||
| d5d9f7c970 | |||
| 63f9449c9a | |||
| e0cff9bcf4 | |||
| 5411db68a8 | |||
| 80804adc68 | |||
| 93edbd1434 | |||
| 3ebec74983 | |||
| 51f5aff58a | |||
| 5369898db7 | |||
| a7497b0aeb | |||
| aaa88fa45f | |||
| ca7395a5ce | |||
| 6ae853c2e6 | |||
| d5fb5337a0 | |||
| 512a188c7a | |||
| ad17266273 | |||
| 78acfa456f | |||
| 0b3b3a22d2 | |||
| 384b598fcf | |||
| b2fe305a84 | |||
| 68d8f3be38 | |||
| 9ac2aa88e6 | |||
| 18700f1e82 | |||
| 0afc9b6be0 | |||
| bda803fbdd | |||
| 105136494c | |||
| ce11079f19 | |||
| 784a54a390 | |||
| bdb7febf9c | |||
| e76272b619 | |||
| cf0dff049b | |||
| 28f5c33d65 | |||
| 5b82118158 | |||
| 125ec1dbcf | |||
| c545fcf896 | |||
| 0ec895c378 | |||
| 406e6f484c | |||
| b63d724e85 | |||
| c73b773724 | |||
| d467313d0c |
@@ -46,7 +46,7 @@ jobs:
|
|||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
- name: audit
|
- name: audit
|
||||||
run: pnpm audit
|
run: pnpm audit
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
paths:
|
paths:
|
||||||
- '.github/workflows/check-generated-files.yml'
|
- '.github/workflows/check-generated-files.yml'
|
||||||
|
- pnpm-lock.yaml
|
||||||
- '**/guest-js/**'
|
- '**/guest-js/**'
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
@@ -27,94 +28,117 @@ jobs:
|
|||||||
filters: |
|
filters: |
|
||||||
autostart:
|
autostart:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/autostart/guest-js/**
|
- plugins/autostart/guest-js/**
|
||||||
- plugins/autostart/src/api-iife.js
|
- plugins/autostart/src/api-iife.js
|
||||||
cli:
|
cli:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/cli/guest-js/**
|
- plugins/cli/guest-js/**
|
||||||
- plugins/cli/src/api-iife.js
|
- plugins/cli/src/api-iife.js
|
||||||
clipboard-manager:
|
clipboard-manager:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/clipboard-manager/guest-js/**
|
- plugins/clipboard-manager/guest-js/**
|
||||||
- plugins/clipboard-manager/src/api-iife.js
|
- plugins/clipboard-manager/src/api-iife.js
|
||||||
dialog:
|
dialog:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/dialog/guest-js/**
|
- plugins/dialog/guest-js/**
|
||||||
- plugins/dialog/src/api-iife.js
|
- plugins/dialog/src/api-iife.js
|
||||||
fs:
|
fs:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/fs/guest-js/**
|
- plugins/fs/guest-js/**
|
||||||
- plugins/fs/src/api-iife.js
|
- plugins/fs/src/api-iife.js
|
||||||
geolocation:
|
geolocation:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/geolocation/guest-js/**
|
- plugins/geolocation/guest-js/**
|
||||||
- plugins/geolocation/src/api-iife.js
|
- plugins/geolocation/src/api-iife.js
|
||||||
global-shortcut:
|
global-shortcut:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/global-shortcut/guest-js/**
|
- plugins/global-shortcut/guest-js/**
|
||||||
- plugins/global-shortcut/src/api-iife.js
|
- plugins/global-shortcut/src/api-iife.js
|
||||||
opener:
|
opener:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/opener/guest-js/**
|
- plugins/opener/guest-js/**
|
||||||
- plugins/opener/src/api-iife.js
|
- plugins/opener/src/api-iife.js
|
||||||
haptics:
|
haptics:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/haptics/guest-js/**
|
- plugins/haptics/guest-js/**
|
||||||
- plugins/haptics/src/api-iife.js
|
- plugins/haptics/src/api-iife.js
|
||||||
http:
|
http:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/http/guest-js/**
|
- plugins/http/guest-js/**
|
||||||
- plugins/http/src/api-iife.js
|
- plugins/http/src/api-iife.js
|
||||||
log:
|
log:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/log/guest-js/**
|
- plugins/log/guest-js/**
|
||||||
- plugins/log/src/api-iife.js
|
- plugins/log/src/api-iife.js
|
||||||
notification:
|
notification:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/notification/guest-js/**
|
- plugins/notification/guest-js/**
|
||||||
- plugins/notification/src/api-iife.js
|
- plugins/notification/src/api-iife.js
|
||||||
os:
|
os:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/os/guest-js/**
|
- plugins/os/guest-js/**
|
||||||
- plugins/os/src/api-iife.js
|
- plugins/os/src/api-iife.js
|
||||||
positioner:
|
positioner:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/positioner/guest-js/**
|
- plugins/positioner/guest-js/**
|
||||||
- plugins/positioner/src/api-iife.js
|
- plugins/positioner/src/api-iife.js
|
||||||
process:
|
process:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/process/guest-js/**
|
- plugins/process/guest-js/**
|
||||||
- plugins/process/src/api-iife.js
|
- plugins/process/src/api-iife.js
|
||||||
shell:
|
shell:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/shell/guest-js/**
|
- plugins/shell/guest-js/**
|
||||||
- plugins/shell/src/api-iife.js
|
- plugins/shell/src/api-iife.js
|
||||||
sql:
|
sql:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/sql/guest-js/**
|
- plugins/sql/guest-js/**
|
||||||
- plugins/sql/src/api-iife.js
|
- plugins/sql/src/api-iife.js
|
||||||
store:
|
store:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/store/guest-js/**
|
- plugins/store/guest-js/**
|
||||||
- plugins/store/src/api-iife.js
|
- plugins/store/src/api-iife.js
|
||||||
stronghold:
|
stronghold:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/stronghold/guest-js/**
|
- plugins/stronghold/guest-js/**
|
||||||
- plugins/stronghold/src/api-iife.js
|
- plugins/stronghold/src/api-iife.js
|
||||||
updater:
|
updater:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/updater/guest-js/**
|
- plugins/updater/guest-js/**
|
||||||
- plugins/updater/src/api-iife.js
|
- plugins/updater/src/api-iife.js
|
||||||
upload:
|
upload:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/upload/guest-js/**
|
- plugins/upload/guest-js/**
|
||||||
- plugins/upload/src/api-iife.js
|
- plugins/upload/src/api-iife.js
|
||||||
websocket:
|
websocket:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/websocket/guest-js/**
|
- plugins/websocket/guest-js/**
|
||||||
- plugins/websocket/src/api-iife.js
|
- plugins/websocket/src/api-iife.js
|
||||||
window-state:
|
window-state:
|
||||||
- .github/workflows/check-generated-files.yml
|
- .github/workflows/check-generated-files.yml
|
||||||
|
- pnpm-lock.yaml
|
||||||
- plugins/window-state/guest-js/**
|
- plugins/window-state/guest-js/**
|
||||||
- plugins/window-state/src/api-iife.js
|
- plugins/window-state/src/api-iife.js
|
||||||
|
|
||||||
@@ -143,7 +167,7 @@ jobs:
|
|||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
|
|
||||||
- name: build api
|
- name: build api
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
|
|
||||||
- name: cargo login
|
- name: cargo login
|
||||||
@@ -75,7 +75,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Create Pull Request With Versions Bumped
|
- name: Create Pull Request With Versions Bumped
|
||||||
id: cpr
|
id: cpr
|
||||||
uses: tauri-apps/create-pull-request@v3
|
uses: peter-evans/create-pull-request@dd2324fc52d5d43c699a5636bcf19fceaa70c284 # 7.0.7
|
||||||
if: steps.covector.outputs.commandRan == 'version'
|
if: steps.covector.outputs.commandRan == 'version'
|
||||||
with:
|
with:
|
||||||
title: 'Publish New Versions (${{ github.ref_name }})'
|
title: 'Publish New Versions (${{ github.ref_name }})'
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
- run: pnpm format:check
|
- run: pnpm format:check
|
||||||
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ jobs:
|
|||||||
node-version: 'lts/*'
|
node-version: 'lts/*'
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
- name: eslint
|
- name: eslint
|
||||||
run: pnpm lint
|
run: pnpm lint
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ jobs:
|
|||||||
|
|
||||||
- uses: pnpm/action-setup@v4
|
- uses: pnpm/action-setup@v4
|
||||||
with:
|
with:
|
||||||
version: 9.x.x
|
version: 10.x.x
|
||||||
run_install: true
|
run_install: true
|
||||||
|
|
||||||
- name: Build packages
|
- name: Build packages
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ target/
|
|||||||
|
|
||||||
# .vscode workspace settings file
|
# .vscode workspace settings file
|
||||||
.vscode/settings.json
|
.vscode/settings.json
|
||||||
|
.vscode/launch.json
|
||||||
|
.vscode/tasks.json
|
||||||
|
|
||||||
# npm, yarn and bun lock files
|
# npm, yarn and bun lock files
|
||||||
package-lock.json
|
package-lock.json
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"singleQuote": true,
|
"singleQuote": true,
|
||||||
"semi": false,
|
"semi": false,
|
||||||
"trailingComma": "none"
|
"trailingComma": "none",
|
||||||
|
"experimentalOperatorPosition": "start"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,8 @@ const ignore = [
|
|||||||
|
|
||||||
async function checkFile(file) {
|
async function checkFile(file) {
|
||||||
if (
|
if (
|
||||||
extensions.some((e) => file.endsWith(e)) &&
|
extensions.some((e) => file.endsWith(e))
|
||||||
!ignore.some((i) => file.includes(`${path.sep}${i}`))
|
&& !ignore.some((i) => file.includes(`${path.sep}${i}`))
|
||||||
) {
|
) {
|
||||||
const fileStream = fs.createReadStream(file)
|
const fileStream = fs.createReadStream(file)
|
||||||
const rl = readline.createInterface({
|
const rl = readline.createInterface({
|
||||||
@@ -46,10 +46,10 @@ async function checkFile(file) {
|
|||||||
for await (let line of rl) {
|
for await (let line of rl) {
|
||||||
// ignore empty lines, allow shebang, swift-tools-version and bundler license
|
// ignore empty lines, allow shebang, swift-tools-version and bundler license
|
||||||
if (
|
if (
|
||||||
line.length === 0 ||
|
line.length === 0
|
||||||
line.startsWith('#!') ||
|
|| line.startsWith('#!')
|
||||||
line.startsWith('// swift-tools-version:') ||
|
|| line.startsWith('// swift-tools-version:')
|
||||||
ignoredLicenses.includes(line)
|
|| ignoredLicenses.includes(line)
|
||||||
) {
|
) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1 +1,2 @@
|
|||||||
plugins/*/permissions/autogenerated/
|
plugins/*/permissions/autogenerated/
|
||||||
|
plugins/*/android/.tauri/tauri-api/build/
|
||||||
|
|||||||
Generated
+513
-392
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,63 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.18]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `http-js@2.4.1`
|
||||||
|
|
||||||
|
## \[2.0.17]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log-js@2.3.1`
|
||||||
|
|
||||||
|
## \[2.0.16]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `clipboard-manager-js@2.2.2`
|
||||||
|
- Upgraded to `notification-js@2.2.2`
|
||||||
|
- Upgraded to `os-js@2.2.1`
|
||||||
|
- Upgraded to `http-js@2.4.0`
|
||||||
|
- Upgraded to `log-js@2.3.0`
|
||||||
|
- Upgraded to `updater-js@2.6.0`
|
||||||
|
|
||||||
|
## \[2.0.15]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log-js@2.2.3`
|
||||||
|
- Upgraded to `opener-js@2.2.6`
|
||||||
|
|
||||||
|
## \[2.0.14]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log-js@2.2.2`
|
||||||
|
- Upgraded to `updater-js@2.5.1`
|
||||||
|
|
||||||
|
## \[2.0.13]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `updater-js@2.5.0`
|
||||||
|
|
||||||
|
## \[2.0.12]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `clipboard-manager-js@2.2.1`
|
||||||
|
- Upgraded to `http-js@2.3.0`
|
||||||
|
- Upgraded to `log-js@2.2.1`
|
||||||
|
- Upgraded to `updater-js@2.4.0`
|
||||||
|
|
||||||
|
## \[2.0.11]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `opener-js@2.2.5`
|
||||||
|
|
||||||
## \[2.0.10]
|
## \[2.0.10]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
+16
-16
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "api",
|
"name": "api",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "2.0.10",
|
"version": "2.0.18",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite --clearScreen false",
|
"dev": "vite --clearScreen false",
|
||||||
@@ -10,35 +10,35 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.2.0",
|
"@tauri-apps/api": "2.3.0",
|
||||||
"@tauri-apps/plugin-barcode-scanner": "^2.2.0",
|
"@tauri-apps/plugin-barcode-scanner": "^2.2.0",
|
||||||
"@tauri-apps/plugin-biometric": "^2.2.0",
|
"@tauri-apps/plugin-biometric": "^2.2.0",
|
||||||
"@tauri-apps/plugin-cli": "^2.2.0",
|
"@tauri-apps/plugin-cli": "^2.2.0",
|
||||||
"@tauri-apps/plugin-clipboard-manager": "^2.2.0",
|
"@tauri-apps/plugin-clipboard-manager": "^2.2.2",
|
||||||
"@tauri-apps/plugin-dialog": "^2.2.0",
|
"@tauri-apps/plugin-dialog": "^2.2.0",
|
||||||
"@tauri-apps/plugin-fs": "^2.2.0",
|
"@tauri-apps/plugin-fs": "^2.2.0",
|
||||||
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
"@tauri-apps/plugin-geolocation": "^2.2.0",
|
||||||
"@tauri-apps/plugin-global-shortcut": "^2.2.0",
|
"@tauri-apps/plugin-global-shortcut": "^2.2.0",
|
||||||
"@tauri-apps/plugin-opener": "^2.2.4",
|
|
||||||
"@tauri-apps/plugin-haptics": "^2.2.0",
|
"@tauri-apps/plugin-haptics": "^2.2.0",
|
||||||
"@tauri-apps/plugin-http": "^2.2.0",
|
"@tauri-apps/plugin-http": "^2.4.1",
|
||||||
"@tauri-apps/plugin-nfc": "^2.2.0",
|
"@tauri-apps/plugin-nfc": "^2.2.0",
|
||||||
"@tauri-apps/plugin-notification": "^2.2.1",
|
"@tauri-apps/plugin-notification": "^2.2.2",
|
||||||
"@tauri-apps/plugin-os": "^2.2.0",
|
"@tauri-apps/plugin-opener": "^2.2.6",
|
||||||
|
"@tauri-apps/plugin-os": "^2.2.1",
|
||||||
"@tauri-apps/plugin-process": "^2.2.0",
|
"@tauri-apps/plugin-process": "^2.2.0",
|
||||||
"@tauri-apps/plugin-shell": "^2.2.0",
|
"@tauri-apps/plugin-shell": "^2.2.0",
|
||||||
"@tauri-apps/plugin-store": "^2.2.0",
|
"@tauri-apps/plugin-store": "^2.2.0",
|
||||||
"@tauri-apps/plugin-updater": "^2.2.0",
|
"@tauri-apps/plugin-updater": "^2.6.0",
|
||||||
"@zerodevx/svelte-json-view": "1.0.11"
|
"@zerodevx/svelte-json-view": "1.0.11"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@iconify-json/codicon": "^1.2.6",
|
"@iconify-json/codicon": "^1.2.12",
|
||||||
"@iconify-json/ph": "^1.2.1",
|
"@iconify-json/ph": "^1.2.2",
|
||||||
"@sveltejs/vite-plugin-svelte": "^5.0.1",
|
"@sveltejs/vite-plugin-svelte": "^5.0.3",
|
||||||
"@tauri-apps/cli": "2.2.4",
|
"@tauri-apps/cli": "2.3.1",
|
||||||
"@unocss/extractor-svelte": "^65.0.0",
|
"@unocss/extractor-svelte": "^66.0.0",
|
||||||
"svelte": "^5.10.0",
|
"svelte": "^5.20.4",
|
||||||
"unocss": "^65.0.0",
|
"unocss": "^66.0.0",
|
||||||
"vite": "^6.0.3"
|
"vite": "^6.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,67 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.0.22]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `http@2.4.1`
|
||||||
|
|
||||||
|
## \[2.0.21]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log@2.3.1`
|
||||||
|
|
||||||
|
## \[2.0.20]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `clipboard-manager@2.2.2`
|
||||||
|
- Upgraded to `geolocation@2.2.4`
|
||||||
|
- Upgraded to `haptics@2.2.4`
|
||||||
|
- Upgraded to `notification@2.2.2`
|
||||||
|
- Upgraded to `os@2.2.1`
|
||||||
|
- Upgraded to `http@2.4.0`
|
||||||
|
- Upgraded to `log@2.3.0`
|
||||||
|
- Upgraded to `updater@2.6.0`
|
||||||
|
|
||||||
|
## \[2.0.19]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log@2.2.3`
|
||||||
|
- Upgraded to `opener@2.2.6`
|
||||||
|
|
||||||
|
## \[2.0.18]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `log@2.2.2`
|
||||||
|
- Upgraded to `updater@2.5.1`
|
||||||
|
|
||||||
|
## \[2.0.17]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `updater@2.5.0`
|
||||||
|
|
||||||
|
## \[2.0.16]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `clipboard-manager@2.2.1`
|
||||||
|
- Upgraded to `http@2.3.0`
|
||||||
|
- Upgraded to `log@2.2.1`
|
||||||
|
- Upgraded to `updater@2.4.0`
|
||||||
|
|
||||||
|
## \[2.0.15]
|
||||||
|
|
||||||
|
### Dependencies
|
||||||
|
|
||||||
|
- Upgraded to `haptics@2.2.3`
|
||||||
|
- Upgraded to `geolocation@2.2.3`
|
||||||
|
- Upgraded to `opener@2.2.5`
|
||||||
|
|
||||||
## \[2.0.14]
|
## \[2.0.14]
|
||||||
|
|
||||||
### Dependencies
|
### Dependencies
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "api"
|
name = "api"
|
||||||
publish = false
|
publish = false
|
||||||
version = "2.0.14"
|
version = "2.0.22"
|
||||||
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 }
|
||||||
@@ -19,21 +19,21 @@ serde_json = { workspace = true }
|
|||||||
serde = { workspace = true }
|
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.2.0" }
|
tauri-plugin-log = { path = "../../../plugins/log", version = "2.3.1" }
|
||||||
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.2.0", features = [
|
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.2.0", features = [
|
||||||
"watch",
|
"watch",
|
||||||
] }
|
] }
|
||||||
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.2.0" }
|
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.2.2" }
|
||||||
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.2.0" }
|
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.2.0" }
|
||||||
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
tauri-plugin-http = { path = "../../../plugins/http", features = [
|
||||||
"multipart",
|
"multipart",
|
||||||
], version = "2.2.0" }
|
], version = "2.4.1" }
|
||||||
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.2.1", features = [
|
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.2.2", features = [
|
||||||
"windows7-compat",
|
"windows7-compat",
|
||||||
] }
|
] }
|
||||||
tauri-plugin-os = { path = "../../../plugins/os", version = "2.2.0" }
|
tauri-plugin-os = { path = "../../../plugins/os", version = "2.2.1" }
|
||||||
tauri-plugin-process = { path = "../../../plugins/process", version = "2.2.0" }
|
tauri-plugin-process = { path = "../../../plugins/process", version = "2.2.0" }
|
||||||
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.2.4" }
|
tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.2.6" }
|
||||||
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.2.0" }
|
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.2.0" }
|
||||||
tauri-plugin-store = { path = "../../../plugins/store", version = "2.2.0" }
|
tauri-plugin-store = { path = "../../../plugins/store", version = "2.2.0" }
|
||||||
|
|
||||||
@@ -53,15 +53,15 @@ features = [
|
|||||||
[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]
|
||||||
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.2.0" }
|
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.2.0" }
|
||||||
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.2.0" }
|
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.2.0" }
|
||||||
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.3.1" }
|
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.6.0" }
|
||||||
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
|
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
|
||||||
|
|
||||||
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
|
||||||
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.2.0" }
|
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.2.0" }
|
||||||
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.2.0" }
|
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.2.0" }
|
||||||
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.2.0" }
|
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.2.0" }
|
||||||
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.2.2" }
|
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.2.4" }
|
||||||
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.2.2" }
|
tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.2.4" }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
prod = ["tauri/custom-protocol"]
|
prod = ["tauri/custom-protocol"]
|
||||||
|
|||||||
+18
-15
@@ -11,26 +11,29 @@
|
|||||||
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "9.18.0",
|
"@eslint/js": "9.22.0",
|
||||||
"@rollup/plugin-node-resolve": "16.0.0",
|
"@rollup/plugin-node-resolve": "16.0.1",
|
||||||
"@rollup/plugin-terser": "0.4.4",
|
"@rollup/plugin-terser": "0.4.4",
|
||||||
"@rollup/plugin-typescript": "11.1.6",
|
"@rollup/plugin-typescript": "12.1.2",
|
||||||
"@types/eslint__js": "8.42.3",
|
"covector": "^0.12.4",
|
||||||
"covector": "^0.12.3",
|
"eslint": "9.22.0",
|
||||||
"eslint": "9.18.0",
|
"eslint-config-prettier": "10.1.1",
|
||||||
"eslint-config-prettier": "9.1.0",
|
|
||||||
"eslint-plugin-security": "3.0.1",
|
"eslint-plugin-security": "3.0.1",
|
||||||
"prettier": "3.4.2",
|
"prettier": "3.5.3",
|
||||||
"rollup": "4.30.1",
|
"rollup": "4.35.0",
|
||||||
"tslib": "2.8.1",
|
"tslib": "2.8.1",
|
||||||
"typescript": "5.7.3",
|
"typescript": "5.8.2",
|
||||||
"typescript-eslint": "8.19.1"
|
"typescript-eslint": "8.26.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"pnpm": {
|
||||||
"semver": ">=7.5.2",
|
"overrides": {
|
||||||
"optionator": ">=0.9.3"
|
"esbuild@<0.25.0": ">=0.25.0"
|
||||||
|
},
|
||||||
|
"onlyBuiltDependencies": [
|
||||||
|
"esbuild"
|
||||||
|
]
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"pnpm": "^9.0.0"
|
"pnpm": "^10.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.2]
|
||||||
|
|
||||||
|
### bug
|
||||||
|
|
||||||
|
- [`d37bbdef`](https://github.com/tauri-apps/plugins-workspace/commit/d37bbdef8dc70e61e59f9fe0bb8b2a48999d0aa1) ([#2507](https://github.com/tauri-apps/plugins-workspace/pull/2507) by [@SquitchYT](https://github.com/tauri-apps/plugins-workspace/../../SquitchYT)) Fix clipboard-manager Wayland support.
|
||||||
|
|
||||||
|
## \[2.2.1]
|
||||||
|
|
||||||
|
- [`ce11079f`](https://github.com/tauri-apps/plugins-workspace/commit/ce11079f19852fbefdecf0e4c7d947af3624fee0) ([#2280](https://github.com/tauri-apps/plugins-workspace/pull/2280) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Explicitly drop `arboard::Clipboard` on exit. Add recommendation to not use read methods on the mainthread.
|
||||||
|
|
||||||
## \[2.2.0]
|
## \[2.2.0]
|
||||||
|
|
||||||
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-clipboard-manager"
|
name = "tauri-plugin-clipboard-manager"
|
||||||
version = "2.2.0"
|
version = "2.2.2"
|
||||||
description = "Read and write to the system clipboard."
|
description = "Read and write to the system clipboard."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -36,4 +36,4 @@ thiserror = { workspace = true }
|
|||||||
tauri = { workspace = true, features = ["wry"] }
|
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 = { version = "3", features = ["wayland-data-control"] }
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_CLIPBOARD_MANAGER__=function(e){"use strict";var t;async function r(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}"function"==typeof SuppressedError&&SuppressedError;class n{get rid(){return function(e,t,r,n){if("a"===r&&!n)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!n:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}(this,t,"f")}constructor(e){t.set(this,void 0),function(e,t,r){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");t.set(e,r)}(this,t,e)}async close(){return r("plugin:resources|close",{rid:this.rid})}}t=new WeakMap;class a extends n{constructor(e){super(e)}static async new(e,t,n){return r("plugin:image|new",{rgba:i(e),width:t,height:n}).then((e=>new a(e)))}static async fromBytes(e){return r("plugin:image|from_bytes",{bytes:i(e)}).then((e=>new a(e)))}static async fromPath(e){return r("plugin:image|from_path",{path:e}).then((e=>new a(e)))}async rgba(){return r("plugin:image|rgba",{rid:this.rid}).then((e=>new Uint8Array(e)))}async size(){return r("plugin:image|size",{rid:this.rid})}}function i(e){return null==e?null:"string"==typeof e?e:e instanceof a?e.rid:e}return e.clear=async function(){await r("plugin:clipboard-manager|clear")},e.readImage=async function(){return await r("plugin:clipboard-manager|read_image").then((e=>new a(e)))},e.readText=async function(){return await r("plugin:clipboard-manager|read_text")},e.writeHtml=async function(e,t){await r("plugin:clipboard-manager|write_html",{html:e,altText:t})},e.writeImage=async function(e){await r("plugin:clipboard-manager|write_image",{image:i(e)})},e.writeText=async function(e,t){await r("plugin:clipboard-manager|write_text",{label:t?.label,text:e})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_PLUGIN_CLIPBOARD_MANAGER__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_CLIPBOARD_MANAGER__=function(e){"use strict";var n;async function t(e,n={},t){return window.__TAURI_INTERNALS__.invoke(e,n,t)}"function"==typeof SuppressedError&&SuppressedError;class r{get rid(){return function(e,n,t,r){if("function"==typeof n||!n.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?r:"a"===t?r.call(e):r?r.value:n.get(e)}(this,n,"f")}constructor(e){n.set(this,void 0),function(e,n,t){if("function"==typeof n||!n.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");n.set(e,t)}(this,n,e)}async close(){return t("plugin:resources|close",{rid:this.rid})}}n=new WeakMap;class a extends r{constructor(e){super(e)}static async new(e,n,r){return t("plugin:image|new",{rgba:i(e),width:n,height:r}).then((e=>new a(e)))}static async fromBytes(e){return t("plugin:image|from_bytes",{bytes:i(e)}).then((e=>new a(e)))}static async fromPath(e){return t("plugin:image|from_path",{path:e}).then((e=>new a(e)))}async rgba(){return t("plugin:image|rgba",{rid:this.rid}).then((e=>new Uint8Array(e)))}async size(){return t("plugin:image|size",{rid:this.rid})}}function i(e){return null==e?null:"string"==typeof e?e:e instanceof a?e.rid:e}return e.clear=async function(){await t("plugin:clipboard-manager|clear")},e.readImage=async function(){return await t("plugin:clipboard-manager|read_image").then((e=>new a(e)))},e.readText=async function(){return await t("plugin:clipboard-manager|read_text")},e.writeHtml=async function(e,n){await t("plugin:clipboard-manager|write_html",{html:e,altText:n})},e.writeImage=async function(e){await t("plugin:clipboard-manager|write_image",{image:i(e)})},e.writeText=async function(e,n){await t("plugin:clipboard-manager|write_text",{label:n?.label,text:e})},e}({});Object.defineProperty(window.__TAURI__,"clipboardManager",{value:__TAURI_PLUGIN_CLIPBOARD_MANAGER__})}
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ async function writeImage(
|
|||||||
* import { readImage } from '@tauri-apps/plugin-clipboard-manager';
|
* import { readImage } from '@tauri-apps/plugin-clipboard-manager';
|
||||||
*
|
*
|
||||||
* const clipboardImage = await readImage();
|
* const clipboardImage = await readImage();
|
||||||
* const blob = new Blob([await clipboardImage.rbga()], { type: 'image' })
|
* const blob = new Blob([await clipboardImage.rgba()], { type: 'image' })
|
||||||
* const url = URL.createObjectURL(blob)
|
* const url = URL.createObjectURL(blob)
|
||||||
* ```
|
* ```
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-clipboard-manager",
|
"name": "@tauri-apps/plugin-clipboard-manager",
|
||||||
"version": "2.2.0",
|
"version": "2.2.2",
|
||||||
"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"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
|
|||||||
) -> crate::Result<Clipboard<R>> {
|
) -> crate::Result<Clipboard<R>> {
|
||||||
Ok(Clipboard {
|
Ok(Clipboard {
|
||||||
app: app.clone(),
|
app: app.clone(),
|
||||||
clipboard: arboard::Clipboard::new().map(Mutex::new),
|
clipboard: arboard::Clipboard::new().map(|c| Mutex::new(Some(c))),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -22,13 +22,21 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
|
|||||||
pub struct Clipboard<R: Runtime> {
|
pub struct Clipboard<R: Runtime> {
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
app: AppHandle<R>,
|
app: AppHandle<R>,
|
||||||
clipboard: Result<Mutex<arboard::Clipboard>, arboard::Error>,
|
// According to arboard docs the clipboard must be dropped before exit.
|
||||||
|
// Since tauri doesn't call drop on exit we'll use an Option to take() on RunEvent::Exit.
|
||||||
|
clipboard: Result<Mutex<Option<arboard::Clipboard>>, arboard::Error>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Runtime> Clipboard<R> {
|
impl<R: Runtime> Clipboard<R> {
|
||||||
pub fn write_text<'a, T: Into<Cow<'a, str>>>(&self, text: T) -> crate::Result<()> {
|
pub fn write_text<'a, T: Into<Cow<'a, str>>>(&self, text: T) -> crate::Result<()> {
|
||||||
match &self.clipboard {
|
match &self.clipboard {
|
||||||
Ok(clipboard) => clipboard.lock().unwrap().set_text(text).map_err(Into::into),
|
Ok(clipboard) => clipboard
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.set_text(text)
|
||||||
|
.map_err(Into::into),
|
||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -38,6 +46,8 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
Ok(clipboard) => clipboard
|
Ok(clipboard) => clipboard
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.set_image(ImageData {
|
.set_image(ImageData {
|
||||||
bytes: Cow::Borrowed(image.rgba()),
|
bytes: Cow::Borrowed(image.rgba()),
|
||||||
width: image.width() as usize,
|
width: image.width() as usize,
|
||||||
@@ -48,10 +58,11 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Warning: This method should not be used on the main thread! Otherwise the underlying libraries may deadlock on Linux, freezing the whole app, when trying to copy data copied from this app, for example if the user copies text from the WebView.
|
||||||
pub fn read_text(&self) -> crate::Result<String> {
|
pub fn read_text(&self) -> crate::Result<String> {
|
||||||
match &self.clipboard {
|
match &self.clipboard {
|
||||||
Ok(clipboard) => {
|
Ok(clipboard) => {
|
||||||
let text = clipboard.lock().unwrap().get_text()?;
|
let text = clipboard.lock().unwrap().as_mut().unwrap().get_text()?;
|
||||||
Ok(text)
|
Ok(text)
|
||||||
}
|
}
|
||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
@@ -67,6 +78,8 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
Ok(clipboard) => clipboard
|
Ok(clipboard) => clipboard
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
.set_html(html, alt_text)
|
.set_html(html, alt_text)
|
||||||
.map_err(Into::into),
|
.map_err(Into::into),
|
||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
@@ -75,15 +88,22 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
|
|
||||||
pub fn clear(&self) -> crate::Result<()> {
|
pub fn clear(&self) -> crate::Result<()> {
|
||||||
match &self.clipboard {
|
match &self.clipboard {
|
||||||
Ok(clipboard) => clipboard.lock().unwrap().clear().map_err(Into::into),
|
Ok(clipboard) => clipboard
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
.clear()
|
||||||
|
.map_err(Into::into),
|
||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Warning: This method should not be used on the main thread! Otherwise the underlying libraries may deadlock on Linux, freezing the whole app, when trying to copy data copied from this app, for example if the user copies text from the WebView.
|
||||||
pub fn read_image(&self) -> crate::Result<Image<'_>> {
|
pub fn read_image(&self) -> crate::Result<Image<'_>> {
|
||||||
match &self.clipboard {
|
match &self.clipboard {
|
||||||
Ok(clipboard) => {
|
Ok(clipboard) => {
|
||||||
let image = clipboard.lock().unwrap().get_image()?;
|
let image = clipboard.lock().unwrap().as_mut().unwrap().get_image()?;
|
||||||
let image = Image::new_owned(
|
let image = Image::new_owned(
|
||||||
image.bytes.to_vec(),
|
image.bytes.to_vec(),
|
||||||
image.width as u32,
|
image.width as u32,
|
||||||
@@ -94,4 +114,10 @@ impl<R: Runtime> Clipboard<R> {
|
|||||||
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
Err(e) => Err(crate::Error::Clipboard(e.to_string())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn cleanup(&self) {
|
||||||
|
if let Ok(clipboard) = &self.clipboard {
|
||||||
|
clipboard.lock().unwrap().take();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@
|
|||||||
|
|
||||||
use tauri::{
|
use tauri::{
|
||||||
plugin::{Builder, TauriPlugin},
|
plugin::{Builder, TauriPlugin},
|
||||||
Manager, Runtime,
|
Manager, RunEvent, Runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
@@ -59,5 +59,11 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
app.manage(clipboard);
|
app.manage(clipboard);
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
|
.on_event(|_app, _event| {
|
||||||
|
#[cfg(desktop)]
|
||||||
|
if let RunEvent::Exit = _event {
|
||||||
|
_app.clipboard().cleanup();
|
||||||
|
}
|
||||||
|
})
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ url = { workspace = true }
|
|||||||
|
|
||||||
[target."cfg(windows)".dependencies]
|
[target."cfg(windows)".dependencies]
|
||||||
dunce = "1"
|
dunce = "1"
|
||||||
windows-registry = "0.4"
|
windows-registry = "0.5"
|
||||||
windows-result = "0.3"
|
windows-result = "0.3"
|
||||||
|
|
||||||
[target."cfg(target_os = \"linux\")".dependencies]
|
[target."cfg(target_os = \"linux\")".dependencies]
|
||||||
|
|||||||
@@ -10,12 +10,12 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tauri-apps/api": "2.2.0",
|
"@tauri-apps/api": "2.3.0",
|
||||||
"@tauri-apps/plugin-deep-link": "2.2.0"
|
"@tauri-apps/plugin-deep-link": "2.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "2.2.4",
|
"@tauri-apps/cli": "2.3.1",
|
||||||
"typescript": "^5.2.2",
|
"typescript": "^5.7.3",
|
||||||
"vite": "^6.0.0"
|
"vite": "^6.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,18 +265,15 @@ mod imp {
|
|||||||
.to_string();
|
.to_string();
|
||||||
|
|
||||||
let key_reg = CURRENT_USER.create(&key_base)?;
|
let key_reg = CURRENT_USER.create(&key_base)?;
|
||||||
key_reg.set_string(
|
key_reg.set_string("", format!("URL:{} protocol", self.app.config().identifier))?;
|
||||||
"",
|
|
||||||
&format!("URL:{} protocol", self.app.config().identifier),
|
|
||||||
)?;
|
|
||||||
key_reg.set_string("URL Protocol", "")?;
|
key_reg.set_string("URL Protocol", "")?;
|
||||||
|
|
||||||
let icon_reg = CURRENT_USER.create(format!("{key_base}\\DefaultIcon"))?;
|
let icon_reg = CURRENT_USER.create(format!("{key_base}\\DefaultIcon"))?;
|
||||||
icon_reg.set_string("", &format!("{exe},0"))?;
|
icon_reg.set_string("", format!("{exe},0"))?;
|
||||||
|
|
||||||
let cmd_reg = CURRENT_USER.create(format!("{key_base}\\shell\\open\\command"))?;
|
let cmd_reg = CURRENT_USER.create(format!("{key_base}\\shell\\open\\command"))?;
|
||||||
|
|
||||||
cmd_reg.set_string("", &format!("\"{exe}\" \"%1\""))?;
|
cmd_reg.set_string("", format!("\"{exe}\" \"%1\""))?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -604,8 +604,8 @@ async function copyFile(
|
|||||||
options?: CopyFileOptions
|
options?: CopyFileOptions
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (
|
if (
|
||||||
(fromPath instanceof URL && fromPath.protocol !== 'file:') ||
|
(fromPath instanceof URL && fromPath.protocol !== 'file:')
|
||||||
(toPath instanceof URL && toPath.protocol !== 'file:')
|
|| (toPath instanceof URL && toPath.protocol !== 'file:')
|
||||||
) {
|
) {
|
||||||
throw new TypeError('Must be a file URL.')
|
throw new TypeError('Must be a file URL.')
|
||||||
}
|
}
|
||||||
@@ -919,8 +919,8 @@ async function rename(
|
|||||||
options?: RenameOptions
|
options?: RenameOptions
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (
|
if (
|
||||||
(oldPath instanceof URL && oldPath.protocol !== 'file:') ||
|
(oldPath instanceof URL && oldPath.protocol !== 'file:')
|
||||||
(newPath instanceof URL && newPath.protocol !== 'file:')
|
|| (newPath instanceof URL && newPath.protocol !== 'file:')
|
||||||
) {
|
) {
|
||||||
throw new TypeError('Must be a file URL.')
|
throw new TypeError('Must be a file URL.')
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,10 +53,7 @@ impl FilePath {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_path(self) -> Result<PathBuf> {
|
pub fn into_path(self) -> Result<PathBuf> {
|
||||||
match self {
|
match self {
|
||||||
Self::Url(url) => url
|
Self::Url(url) => url.to_file_path().map_err(|_| Error::InvalidPathUrl),
|
||||||
.to_file_path()
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.map_err(|_| Error::InvalidPathUrl),
|
|
||||||
Self::Path(p) => Ok(p),
|
Self::Path(p) => Ok(p),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -91,10 +88,7 @@ impl SafeFilePath {
|
|||||||
#[inline]
|
#[inline]
|
||||||
pub fn into_path(self) -> Result<PathBuf> {
|
pub fn into_path(self) -> Result<PathBuf> {
|
||||||
match self {
|
match self {
|
||||||
Self::Url(url) => url
|
Self::Url(url) => url.to_file_path().map_err(|_| Error::InvalidPathUrl),
|
||||||
.to_file_path()
|
|
||||||
.map(PathBuf::from)
|
|
||||||
.map_err(|_| Error::InvalidPathUrl),
|
|
||||||
Self::Path(p) => Ok(p.as_ref().to_owned()),
|
Self::Path(p) => Ok(p.as_ref().to_owned()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.4]
|
||||||
|
|
||||||
|
- [`a1b3fa27`](https://github.com/tauri-apps/plugins-workspace/commit/a1b3fa27f11022c9b6622b4fab12d93239eb05de) ([#2515](https://github.com/tauri-apps/plugins-workspace/pull/2515) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Re-exported the `Geolocation`, `Haptics`, `Notification`, and `Os` structs so that they show up on docs.rs.
|
||||||
|
|
||||||
|
## \[2.2.3]
|
||||||
|
|
||||||
|
- [`406e6f48`](https://github.com/tauri-apps/plugins-workspace/commit/406e6f484cdc13d35c50fb949f7489ca9eeccc44) ([#2323](https://github.com/tauri-apps/plugins-workspace/pull/2323) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused build failures when the `haptics` or `geolocation` plugin was used without their `specta` feature flag enabled.
|
||||||
|
|
||||||
## \[2.2.2]
|
## \[2.2.2]
|
||||||
|
|
||||||
- [`c9c13a0f`](https://github.com/tauri-apps/plugins-workspace/commit/c9c13a0fe7cdaac223843f5ba33176252f8e22f5) ([#2316](https://github.com/tauri-apps/plugins-workspace/pull/2316) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) **Breaking change:** `specta` integration is now behind a `specta` feature flag like in Tauri.
|
- [`c9c13a0f`](https://github.com/tauri-apps/plugins-workspace/commit/c9c13a0fe7cdaac223843f5ba33176252f8e22f5) ([#2316](https://github.com/tauri-apps/plugins-workspace/pull/2316) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) **Breaking change:** `specta` integration is now behind a `specta` feature flag like in Tauri.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-geolocation"
|
name = "tauri-plugin-geolocation"
|
||||||
description = "Get and track the device's current position"
|
description = "Get and track the device's current position"
|
||||||
version = "2.2.2"
|
version = "2.2.4"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
|
|||||||
@@ -118,8 +118,8 @@ import {
|
|||||||
|
|
||||||
let permissions = await checkPermissions()
|
let permissions = await checkPermissions()
|
||||||
if (
|
if (
|
||||||
permissions.location === 'prompt' ||
|
permissions.location === 'prompt'
|
||||||
permissions.location === 'prompt-with-rationale'
|
|| permissions.location === 'prompt-with-rationale'
|
||||||
) {
|
) {
|
||||||
permissions = await requestPermissions(['location'])
|
permissions = await requestPermissions(['location'])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_GEOLOCATION__=function(t){"use strict";function n(t,n,e,i){if("a"===e&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof n?t!==n||!i:!n.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===e?i:"a"===e?i.call(t):i?i.value:n.get(t)}function e(t,n,e,i,s){if("function"==typeof n||!n.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return n.set(t,e),e}var i,s,o;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),s.set(this,0),o.set(this,[]),this.id=function(t,n=!1){return window.__TAURI_INTERNALS__.transformCallback(t,n)}((({message:t,id:r})=>{if(r==n(this,s,"f"))for(n(this,i,"f").call(this,t),e(this,s,n(this,s,"f")+1);n(this,s,"f")in n(this,o,"f");){const t=n(this,o,"f")[n(this,s,"f")];n(this,i,"f").call(this,t),delete n(this,o,"f")[n(this,s,"f")],e(this,s,n(this,s,"f")+1)}else n(this,o,"f")[r]=t}))}set onmessage(t){e(this,i,t)}get onmessage(){return n(this,i,"f")}[(i=new WeakMap,s=new WeakMap,o=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}async function c(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return t.checkPermissions=async function(){return await async function(t){return c(`plugin:${t}|check_permissions`)}("geolocation")},t.clearWatch=async function(t){await c("plugin:geolocation|clear_watch",{channelId:t})},t.getCurrentPosition=async function(t){return await c("plugin:geolocation|get_current_position",{options:t})},t.requestPermissions=async function(t){return await c("plugin:geolocation|request_permissions",{permissions:t})},t.watchPosition=async function(t,n){const e=new a;return e.onmessage=t=>{"string"==typeof t?n(null,t):n(t)},await c("plugin:geolocation|watch_position",{options:t,channel:e}),e.id},t}({});Object.defineProperty(window.__TAURI__,"geolocation",{value:__TAURI_PLUGIN_GEOLOCATION__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_GEOLOCATION__=function(t){"use strict";function n(t,n,e,i){if("function"==typeof n||!n.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===e?i:"a"===e?i.call(t):i?i.value:n.get(t)}function e(t,n,e,i,s){if("function"==typeof n||!n.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return n.set(t,e),e}var i,s,o;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),s.set(this,0),o.set(this,[]),this.id=function(t,n=!1){return window.__TAURI_INTERNALS__.transformCallback(t,n)}((({message:t,id:r})=>{if(r==n(this,s,"f"))for(n(this,i,"f").call(this,t),e(this,s,n(this,s,"f")+1);n(this,s,"f")in n(this,o,"f");){const t=n(this,o,"f")[n(this,s,"f")];n(this,i,"f").call(this,t),delete n(this,o,"f")[n(this,s,"f")],e(this,s,n(this,s,"f")+1)}else n(this,o,"f")[r]=t}))}set onmessage(t){e(this,i,t)}get onmessage(){return n(this,i,"f")}[(i=new WeakMap,s=new WeakMap,o=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}async function c(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return t.checkPermissions=async function(){return await async function(t){return c(`plugin:${t}|check_permissions`)}("geolocation")},t.clearWatch=async function(t){await c("plugin:geolocation|clear_watch",{channelId:t})},t.getCurrentPosition=async function(t){return await c("plugin:geolocation|get_current_position",{options:t})},t.requestPermissions=async function(t){return await c("plugin:geolocation|request_permissions",{permissions:t})},t.watchPosition=async function(t,n){const e=new a;return e.onmessage=t=>{"string"==typeof t?n(null,t):n(t)},await c("plugin:geolocation|watch_position",{options:t,channel:e}),e.id},t}({});Object.defineProperty(window.__TAURI__,"geolocation",{value:__TAURI_PLUGIN_GEOLOCATION__})}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-geolocation",
|
"name": "@tauri-apps/plugin-geolocation",
|
||||||
"version": "2.2.2",
|
"version": "2.2.4",
|
||||||
"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"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub enum Error {
|
|||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
PluginInvoke(
|
PluginInvoke(
|
||||||
#[serde(skip)]
|
#[cfg_attr(feature = "specta", serde(skip))]
|
||||||
#[from]
|
#[from]
|
||||||
tauri::plugin::mobile::PluginInvokeError,
|
tauri::plugin::mobile::PluginInvokeError,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ mod models;
|
|||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
use desktop::Geolocation;
|
pub use desktop::Geolocation;
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
use mobile::Geolocation;
|
pub use mobile::Geolocation;
|
||||||
|
|
||||||
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the geolocation APIs.
|
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the geolocation APIs.
|
||||||
pub trait GeolocationExt<R: Runtime> {
|
pub trait GeolocationExt<R: Runtime> {
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_GLOBAL_SHORTCUT__=function(t){"use strict";function e(t,e,r,s){if("a"===r&&!s)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!s:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?s:"a"===r?s.call(t):s?s.value:e.get(t)}function r(t,e,r,s,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,r),r}var s,i,n;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,s.set(this,(()=>{})),i.set(this,0),n.set(this,[]),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:o})=>{if(o==e(this,i,"f"))for(e(this,s,"f").call(this,t),r(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,n,"f");){const t=e(this,n,"f")[e(this,i,"f")];e(this,s,"f").call(this,t),delete e(this,n,"f")[e(this,i,"f")],r(this,i,e(this,i,"f")+1)}else e(this,n,"f")[o]=t}))}set onmessage(t){r(this,s,t)}get onmessage(){return e(this,s,"f")}[(s=new WeakMap,i=new WeakMap,n=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function _(t,e={},r){return window.__TAURI_INTERNALS__.invoke(t,e,r)}return t.isRegistered=async function(t){return await _("plugin:global-shortcut|is_registered",{shortcut:t})},t.register=async function(t,e){const r=new a;return r.onmessage=e,await _("plugin:global-shortcut|register",{shortcuts:Array.isArray(t)?t:[t],handler:r})},t.unregister=async function(t){return await _("plugin:global-shortcut|unregister",{shortcuts:Array.isArray(t)?t:[t]})},t.unregisterAll=async function(){return await _("plugin:global-shortcut|unregister_all",{})},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_PLUGIN_GLOBAL_SHORTCUT__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_GLOBAL_SHORTCUT__=function(t){"use strict";function e(t,e,r,s){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?s:"a"===r?s.call(t):s?s.value:e.get(t)}function r(t,e,r,s,i){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");return e.set(t,r),r}var s,i,n;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,s.set(this,(()=>{})),i.set(this,0),n.set(this,[]),this.id=function(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}((({message:t,id:o})=>{if(o==e(this,i,"f"))for(e(this,s,"f").call(this,t),r(this,i,e(this,i,"f")+1);e(this,i,"f")in e(this,n,"f");){const t=e(this,n,"f")[e(this,i,"f")];e(this,s,"f").call(this,t),delete e(this,n,"f")[e(this,i,"f")],r(this,i,e(this,i,"f")+1)}else e(this,n,"f")[o]=t}))}set onmessage(t){r(this,s,t)}get onmessage(){return e(this,s,"f")}[(s=new WeakMap,i=new WeakMap,n=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function _(t,e={},r){return window.__TAURI_INTERNALS__.invoke(t,e,r)}return t.isRegistered=async function(t){return await _("plugin:global-shortcut|is_registered",{shortcut:t})},t.register=async function(t,e){const r=new a;return r.onmessage=e,await _("plugin:global-shortcut|register",{shortcuts:Array.isArray(t)?t:[t],handler:r})},t.unregister=async function(t){return await _("plugin:global-shortcut|unregister",{shortcuts:Array.isArray(t)?t:[t]})},t.unregisterAll=async function(){return await _("plugin:global-shortcut|unregister_all",{})},t}({});Object.defineProperty(window.__TAURI__,"globalShortcut",{value:__TAURI_PLUGIN_GLOBAL_SHORTCUT__})}
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.4]
|
||||||
|
|
||||||
|
- [`a1b3fa27`](https://github.com/tauri-apps/plugins-workspace/commit/a1b3fa27f11022c9b6622b4fab12d93239eb05de) ([#2515](https://github.com/tauri-apps/plugins-workspace/pull/2515) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Re-exported the `Geolocation`, `Haptics`, `Notification`, and `Os` structs so that they show up on docs.rs.
|
||||||
|
|
||||||
|
## \[2.2.3]
|
||||||
|
|
||||||
|
- [`406e6f48`](https://github.com/tauri-apps/plugins-workspace/commit/406e6f484cdc13d35c50fb949f7489ca9eeccc44) ([#2323](https://github.com/tauri-apps/plugins-workspace/pull/2323) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused build failures when the `haptics` or `geolocation` plugin was used without their `specta` feature flag enabled.
|
||||||
|
|
||||||
## \[2.2.2]
|
## \[2.2.2]
|
||||||
|
|
||||||
- [`c9c13a0f`](https://github.com/tauri-apps/plugins-workspace/commit/c9c13a0fe7cdaac223843f5ba33176252f8e22f5) ([#2316](https://github.com/tauri-apps/plugins-workspace/pull/2316) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) **Breaking change:** `specta` integration is now behind a `specta` feature flag like in Tauri.
|
- [`c9c13a0f`](https://github.com/tauri-apps/plugins-workspace/commit/c9c13a0fe7cdaac223843f5ba33176252f8e22f5) ([#2316](https://github.com/tauri-apps/plugins-workspace/pull/2316) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) **Breaking change:** `specta` integration is now behind a `specta` feature flag like in Tauri.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-haptics"
|
name = "tauri-plugin-haptics"
|
||||||
description = "Haptic feedback and vibrations on Android and iOS"
|
description = "Haptic feedback and vibrations on Android and iOS"
|
||||||
version = "2.2.2"
|
version = "2.2.4"
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
|
|||||||
@@ -69,6 +69,19 @@ fn main() {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Second, add the required permissions in the project:
|
||||||
|
|
||||||
|
`src-tauri/capabilities/default.json`
|
||||||
|
|
||||||
|
```json
|
||||||
|
"permissions": [
|
||||||
|
"haptics:allow-impact-feedback",
|
||||||
|
"haptics:allow-notification-feedback",
|
||||||
|
"haptics:allow-selection-feedback",
|
||||||
|
"haptics:allow-vibrate"
|
||||||
|
]
|
||||||
|
```
|
||||||
|
|
||||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-haptics",
|
"name": "@tauri-apps/plugin-haptics",
|
||||||
"version": "2.2.2",
|
"version": "2.2.4",
|
||||||
"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"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ pub enum Error {
|
|||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
PluginInvoke(
|
PluginInvoke(
|
||||||
#[serde(skip)]
|
#[cfg_attr(feature = "specta", serde(skip))]
|
||||||
#[from]
|
#[from]
|
||||||
tauri::plugin::mobile::PluginInvokeError,
|
tauri::plugin::mobile::PluginInvokeError,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -21,9 +21,9 @@ mod models;
|
|||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
use desktop::Haptics;
|
pub use desktop::Haptics;
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
use mobile::Haptics;
|
pub use mobile::Haptics;
|
||||||
|
|
||||||
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the haptics APIs.
|
/// Extensions to [`tauri::App`], [`tauri::AppHandle`], [`tauri::WebviewWindow`], [`tauri::Webview`] and [`tauri::Window`] to access the haptics APIs.
|
||||||
pub trait HapticsExt<R: Runtime> {
|
pub trait HapticsExt<R: Runtime> {
|
||||||
|
|||||||
@@ -1,5 +1,17 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.4.1]
|
||||||
|
|
||||||
|
- [`d3183aa9`](https://github.com/tauri-apps/plugins-workspace/commit/d3183aa99da7ca67e627394132ddeb3b85ccef06) ([#2522](https://github.com/tauri-apps/plugins-workspace/pull/2522) by [@adrieljss](https://github.com/tauri-apps/plugins-workspace/../../adrieljss)) Fix `fetch` blocking until the whole response is read even if it was a streaming response.
|
||||||
|
|
||||||
|
## \[2.4.0]
|
||||||
|
|
||||||
|
- [`cb38f54f`](https://github.com/tauri-apps/plugins-workspace/commit/cb38f54f4a4ef30995283cd82166c62da17bac44) ([#2479](https://github.com/tauri-apps/plugins-workspace/pull/2479) by [@adrieljss](https://github.com/tauri-apps/plugins-workspace/../../adrieljss)) Add stream support for HTTP stream responses.
|
||||||
|
|
||||||
|
## \[2.3.0]
|
||||||
|
|
||||||
|
- [`10513649`](https://github.com/tauri-apps/plugins-workspace/commit/105136494c5a5bf4b1f1cc06cc71815412d17ec8) ([#2204](https://github.com/tauri-apps/plugins-workspace/pull/2204) by [@RickeyWard](https://github.com/tauri-apps/plugins-workspace/../../RickeyWard)) Add `dangerous-settings` feature flag and new JS `danger` option to disable tls hostname/certificate validation.
|
||||||
|
|
||||||
## \[2.2.0]
|
## \[2.2.0]
|
||||||
|
|
||||||
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-http"
|
name = "tauri-plugin-http"
|
||||||
version = "2.2.0"
|
version = "2.4.1"
|
||||||
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 }
|
||||||
@@ -73,3 +73,4 @@ charset = ["reqwest/charset"]
|
|||||||
macos-system-configuration = ["reqwest/macos-system-configuration"]
|
macos-system-configuration = ["reqwest/macos-system-configuration"]
|
||||||
unsafe-headers = []
|
unsafe-headers = []
|
||||||
tracing = ["dep:tracing"]
|
tracing = ["dep:tracing"]
|
||||||
|
dangerous-settings = []
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_HTTP__=function(e){"use strict";async function t(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}"function"==typeof SuppressedError&&SuppressedError;const r="Request canceled";return e.fetch=async function(e,n){const a=n?.signal;if(a?.aborted)throw new Error(r);const o=n?.maxRedirections,s=n?.connectTimeout,i=n?.proxy;n&&(delete n.maxRedirections,delete n.connectTimeout,delete n.proxy);const d=n?.headers?n.headers instanceof Headers?n.headers:new Headers(n.headers):new Headers,c=new Request(e,n),u=await c.arrayBuffer(),f=0!==u.byteLength?Array.from(new Uint8Array(u)):null;for(const[e,t]of c.headers)d.get(e)||d.set(e,t);const _=(d instanceof Headers?Array.from(d.entries()):Array.isArray(d)?d:Object.entries(d)).map((([e,t])=>[e,"string"==typeof t?t:t.toString()]));if(a?.aborted)throw new Error(r);const h=await t("plugin:http|fetch",{clientConfig:{method:c.method,url:c.url,headers:_,data:f,maxRedirections:o,connectTimeout:s,proxy:i}}),l=()=>t("plugin:http|fetch_cancel",{rid:h});if(a?.aborted)throw l(),new Error(r);a?.addEventListener("abort",(()=>{l()}));const{status:p,statusText:w,url:y,headers:T,rid:A}=await t("plugin:http|fetch_send",{rid:h}),g=await t("plugin:http|fetch_read_body",{rid:A}),R=new Response(g instanceof ArrayBuffer&&0!==g.byteLength?g:g instanceof Array&&g.length>0?new Uint8Array(g):null,{status:p,statusText:w});return Object.defineProperty(R,"url",{value:y}),Object.defineProperty(R,"headers",{value:new Headers(T)}),R},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_PLUGIN_HTTP__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_HTTP__=function(e){"use strict";function t(e,t,r,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===r?n:"a"===r?n.call(e):n?n.value:t.get(e)}function r(e,t,r,n,s){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,r),r}var n,s,a;"function"==typeof SuppressedError&&SuppressedError;const i="__TAURI_TO_IPC_KEY__";class o{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),s.set(this,0),a.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:i})=>{if(i==t(this,s,"f"))for(t(this,n,"f").call(this,e),r(this,s,t(this,s,"f")+1);t(this,s,"f")in t(this,a,"f");){const e=t(this,a,"f")[t(this,s,"f")];t(this,n,"f").call(this,e),delete t(this,a,"f")[t(this,s,"f")],r(this,s,t(this,s,"f")+1)}else t(this,a,"f")[i]=e}))}set onmessage(e){r(this,n,e)}get onmessage(){return t(this,n,"f")}[(n=new WeakMap,s=new WeakMap,a=new WeakMap,i)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[i]()}}async function c(e,t={},r){return window.__TAURI_INTERNALS__.invoke(e,t,r)}const d="Request cancelled";return e.fetch=async function(e,t){const r=t?.signal;if(r?.aborted)throw new Error(d);const n=t?.maxRedirections,s=t?.connectTimeout,a=t?.proxy,i=t?.danger;t&&(delete t.maxRedirections,delete t.connectTimeout,delete t.proxy,delete t.danger);const h=t?.headers?t.headers instanceof Headers?t.headers:new Headers(t.headers):new Headers,f=new Request(e,t),_=await f.arrayBuffer(),u=0!==_.byteLength?Array.from(new Uint8Array(_)):null;for(const[e,t]of f.headers)h.get(e)||h.set(e,t);const l=(h instanceof Headers?Array.from(h.entries()):Array.isArray(h)?h:Object.entries(h)).map((([e,t])=>[e,"string"==typeof t?t:t.toString()]));if(r?.aborted)throw new Error(d);const w=await c("plugin:http|fetch",{clientConfig:{method:f.method,url:f.url,headers:l,data:u,maxRedirections:n,connectTimeout:s,proxy:a,danger:i}}),p=()=>c("plugin:http|fetch_cancel",{rid:w});if(r?.aborted)throw p(),new Error(d);r?.addEventListener("abort",(()=>{p()}));const{status:y,statusText:m,url:T,headers:g,rid:A}=await c("plugin:http|fetch_send",{rid:w}),R=new ReadableStream({start:e=>{const t=new o;t.onmessage=t=>{r?.aborted?e.error(d):(t instanceof ArrayBuffer?0!=t.byteLength:0!=t.length)?e.enqueue(new Uint8Array(t)):e.close()},c("plugin:http|fetch_read_body",{rid:A,streamChannel:t}).catch((t=>{e.error(t)}))}}),b=new Response(R,{status:y,statusText:m});return Object.defineProperty(b,"url",{value:T}),Object.defineProperty(b,"headers",{value:new Headers(g)}),b},e}({});Object.defineProperty(window.__TAURI__,"http",{value:__TAURI_PLUGIN_HTTP__})}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@
|
|||||||
* @module
|
* @module
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { invoke } from '@tauri-apps/api/core'
|
import { Channel, invoke } from '@tauri-apps/api/core'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Configuration of a proxy that a Client should pass requests to.
|
* Configuration of a proxy that a Client should pass requests to.
|
||||||
@@ -84,9 +84,29 @@ export interface ClientOptions {
|
|||||||
* Configuration of a proxy that a Client should pass requests to.
|
* Configuration of a proxy that a Client should pass requests to.
|
||||||
*/
|
*/
|
||||||
proxy?: Proxy
|
proxy?: Proxy
|
||||||
|
/**
|
||||||
|
* Configuration for dangerous settings on the client such as disabling SSL verification.
|
||||||
|
*/
|
||||||
|
danger?: DangerousSettings
|
||||||
}
|
}
|
||||||
|
|
||||||
const ERROR_REQUEST_CANCELLED = 'Request canceled'
|
/**
|
||||||
|
* Configuration for dangerous settings on the client such as disabling SSL verification.
|
||||||
|
*
|
||||||
|
* @since 2.3.0
|
||||||
|
*/
|
||||||
|
export interface DangerousSettings {
|
||||||
|
/**
|
||||||
|
* Disables SSL verification.
|
||||||
|
*/
|
||||||
|
acceptInvalidCerts?: boolean
|
||||||
|
/**
|
||||||
|
* Disables hostname verification.
|
||||||
|
*/
|
||||||
|
acceptInvalidHostnames?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
const ERROR_REQUEST_CANCELLED = 'Request cancelled'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a resource from the network. It returns a `Promise` that resolves to the
|
* Fetch a resource from the network. It returns a `Promise` that resolves to the
|
||||||
@@ -115,12 +135,14 @@ export async function fetch(
|
|||||||
const maxRedirections = init?.maxRedirections
|
const maxRedirections = init?.maxRedirections
|
||||||
const connectTimeout = init?.connectTimeout
|
const connectTimeout = init?.connectTimeout
|
||||||
const proxy = init?.proxy
|
const proxy = init?.proxy
|
||||||
|
const danger = init?.danger
|
||||||
|
|
||||||
// Remove these fields before creating the request
|
// Remove these fields before creating the request
|
||||||
if (init) {
|
if (init) {
|
||||||
delete init.maxRedirections
|
delete init.maxRedirections
|
||||||
delete init.connectTimeout
|
delete init.connectTimeout
|
||||||
delete init.proxy
|
delete init.proxy
|
||||||
|
delete init.danger
|
||||||
}
|
}
|
||||||
|
|
||||||
const headers = init?.headers
|
const headers = init?.headers
|
||||||
@@ -172,7 +194,8 @@ export async function fetch(
|
|||||||
data,
|
data,
|
||||||
maxRedirections,
|
maxRedirections,
|
||||||
connectTimeout,
|
connectTimeout,
|
||||||
proxy
|
proxy,
|
||||||
|
danger
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -206,24 +229,45 @@ export async function fetch(
|
|||||||
rid
|
rid
|
||||||
})
|
})
|
||||||
|
|
||||||
const body = await invoke<ArrayBuffer | number[]>(
|
const readableStreamBody = new ReadableStream({
|
||||||
'plugin:http|fetch_read_body',
|
start: (controller) => {
|
||||||
{
|
const streamChannel = new Channel<ArrayBuffer | number[]>()
|
||||||
rid: responseRid
|
streamChannel.onmessage = (res: ArrayBuffer | number[]) => {
|
||||||
}
|
// close early if aborted
|
||||||
)
|
if (signal?.aborted) {
|
||||||
|
controller.error(ERROR_REQUEST_CANCELLED)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const res = new Response(
|
// close when the signal to close (an empty chunk)
|
||||||
body instanceof ArrayBuffer && body.byteLength !== 0
|
// is sent from the IPC.
|
||||||
? body
|
if (
|
||||||
: body instanceof Array && body.length > 0
|
res instanceof ArrayBuffer ? res.byteLength == 0 : res.length == 0
|
||||||
? new Uint8Array(body)
|
) {
|
||||||
: null,
|
controller.close()
|
||||||
{
|
return
|
||||||
status,
|
}
|
||||||
statusText
|
|
||||||
|
// the content conversion (like .text(), .json(), etc.) in Response
|
||||||
|
// must have Uint8Array as its content, else it will
|
||||||
|
// have untraceable error that's hard to debug.
|
||||||
|
controller.enqueue(new Uint8Array(res))
|
||||||
|
}
|
||||||
|
|
||||||
|
// run a non-blocking body stream fetch
|
||||||
|
invoke('plugin:http|fetch_read_body', {
|
||||||
|
rid: responseRid,
|
||||||
|
streamChannel
|
||||||
|
}).catch((e) => {
|
||||||
|
controller.error(e)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
)
|
})
|
||||||
|
|
||||||
|
const res = new Response(readableStreamBody, {
|
||||||
|
status,
|
||||||
|
statusText
|
||||||
|
})
|
||||||
|
|
||||||
// url and headers are read only properties
|
// url and headers are read only properties
|
||||||
// but seems like we can set them like this
|
// but seems like we can set them like this
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-http",
|
"name": "@tauri-apps/plugin-http",
|
||||||
"version": "2.2.0",
|
"version": "2.4.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 serde::{Deserialize, Serialize};
|
|||||||
use tauri::{
|
use tauri::{
|
||||||
async_runtime::Mutex,
|
async_runtime::Mutex,
|
||||||
command,
|
command,
|
||||||
ipc::{CommandScope, GlobalScope},
|
ipc::{Channel, CommandScope, GlobalScope},
|
||||||
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
|
Manager, ResourceId, ResourceTable, Runtime, State, Webview,
|
||||||
};
|
};
|
||||||
use tokio::sync::oneshot::{channel, Receiver, Sender};
|
use tokio::sync::oneshot::{channel, Receiver, Sender};
|
||||||
@@ -75,6 +75,14 @@ pub struct FetchResponse {
|
|||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
|
#[allow(dead_code)] //feature flags shoudln't affect api
|
||||||
|
pub struct DangerousSettings {
|
||||||
|
accept_invalid_certs: bool,
|
||||||
|
accept_invalid_hostnames: bool,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct ClientConfig {
|
pub struct ClientConfig {
|
||||||
@@ -85,6 +93,7 @@ pub struct ClientConfig {
|
|||||||
connect_timeout: Option<u64>,
|
connect_timeout: Option<u64>,
|
||||||
max_redirections: Option<usize>,
|
max_redirections: Option<usize>,
|
||||||
proxy: Option<Proxy>,
|
proxy: Option<Proxy>,
|
||||||
|
danger: Option<DangerousSettings>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Deserialize)]
|
#[derive(Debug, Deserialize)]
|
||||||
@@ -181,6 +190,7 @@ pub async fn fetch<R: Runtime>(
|
|||||||
connect_timeout,
|
connect_timeout,
|
||||||
max_redirections,
|
max_redirections,
|
||||||
proxy,
|
proxy,
|
||||||
|
danger,
|
||||||
} = client_config;
|
} = client_config;
|
||||||
|
|
||||||
let scheme = url.scheme();
|
let scheme = url.scheme();
|
||||||
@@ -220,6 +230,24 @@ pub async fn fetch<R: Runtime>(
|
|||||||
{
|
{
|
||||||
let mut builder = reqwest::ClientBuilder::new();
|
let mut builder = reqwest::ClientBuilder::new();
|
||||||
|
|
||||||
|
if let Some(danger_config) = danger {
|
||||||
|
#[cfg(not(feature = "dangerous-settings"))]
|
||||||
|
{
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
{
|
||||||
|
eprintln!("[\x1b[33mWARNING\x1b[0m] using dangerous settings requires `dangerous-settings` feature flag in your Cargo.toml");
|
||||||
|
}
|
||||||
|
let _ = danger_config;
|
||||||
|
return Err(Error::DangerousSettings);
|
||||||
|
}
|
||||||
|
#[cfg(feature = "dangerous-settings")]
|
||||||
|
{
|
||||||
|
builder = builder
|
||||||
|
.danger_accept_invalid_certs(danger_config.accept_invalid_certs)
|
||||||
|
.danger_accept_invalid_hostnames(danger_config.accept_invalid_hostnames)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(timeout) = connect_timeout {
|
if let Some(timeout) = connect_timeout {
|
||||||
builder = builder.connect_timeout(Duration::from_millis(timeout));
|
builder = builder.connect_timeout(Duration::from_millis(timeout));
|
||||||
}
|
}
|
||||||
@@ -287,6 +315,7 @@ pub async fn fetch<R: Runtime>(
|
|||||||
tracing::trace!("{:?}", request);
|
tracing::trace!("{:?}", request);
|
||||||
|
|
||||||
let fut = async move { request.send().await.map_err(Into::into) };
|
let fut = async move { request.send().await.map_err(Into::into) };
|
||||||
|
|
||||||
let mut resources_table = webview.resources_table();
|
let mut resources_table = webview.resources_table();
|
||||||
let rid = resources_table.add_request(Box::pin(fut));
|
let rid = resources_table.add_request(Box::pin(fut));
|
||||||
|
|
||||||
@@ -330,7 +359,7 @@ pub fn fetch_cancel<R: Runtime>(webview: Webview<R>, rid: ResourceId) -> crate::
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[command]
|
||||||
pub async fn fetch_send<R: Runtime>(
|
pub async fn fetch_send<R: Runtime>(
|
||||||
webview: Webview<R>,
|
webview: Webview<R>,
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
@@ -382,17 +411,28 @@ pub async fn fetch_send<R: Runtime>(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tauri::command]
|
#[command]
|
||||||
pub(crate) async fn fetch_read_body<R: Runtime>(
|
pub async fn fetch_read_body<R: Runtime>(
|
||||||
webview: Webview<R>,
|
webview: Webview<R>,
|
||||||
rid: ResourceId,
|
rid: ResourceId,
|
||||||
) -> crate::Result<tauri::ipc::Response> {
|
stream_channel: Channel<tauri::ipc::InvokeResponseBody>,
|
||||||
|
) -> crate::Result<()> {
|
||||||
let res = {
|
let res = {
|
||||||
let mut resources_table = webview.resources_table();
|
let mut resources_table = webview.resources_table();
|
||||||
resources_table.take::<ReqwestResponse>(rid)?
|
resources_table.take::<ReqwestResponse>(rid)?
|
||||||
};
|
};
|
||||||
let res = Arc::into_inner(res).unwrap().0;
|
|
||||||
Ok(tauri::ipc::Response::new(res.bytes().await?.to_vec()))
|
let mut res = Arc::into_inner(res).unwrap().0;
|
||||||
|
|
||||||
|
// send response through IPC channel
|
||||||
|
while let Some(chunk) = res.chunk().await? {
|
||||||
|
stream_channel.send(tauri::ipc::InvokeResponseBody::Raw(chunk.to_vec()))?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// send empty vector when done
|
||||||
|
stream_channel.send(tauri::ipc::InvokeResponseBody::Raw(Vec::new()))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
// forbidden headers per fetch spec https://fetch.spec.whatwg.org/#terminology-headers
|
// forbidden headers per fetch spec https://fetch.spec.whatwg.org/#terminology-headers
|
||||||
|
|||||||
@@ -41,6 +41,8 @@ pub enum Error {
|
|||||||
Tauri(#[from] tauri::Error),
|
Tauri(#[from] tauri::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Utf8(#[from] std::string::FromUtf8Error),
|
Utf8(#[from] std::string::FromUtf8Error),
|
||||||
|
#[error("dangerous settings used but are not enabled")]
|
||||||
|
DangerousSettings,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for Error {
|
impl Serialize for Error {
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
|||||||
commands::fetch,
|
commands::fetch,
|
||||||
commands::fetch_cancel,
|
commands::fetch_cancel,
|
||||||
commands::fetch_send,
|
commands::fetch_send,
|
||||||
commands::fetch_read_body,
|
commands::fetch_read_body
|
||||||
])
|
])
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,27 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.3.1]
|
||||||
|
|
||||||
|
- [`1bb1ced5`](https://github.com/tauri-apps/plugins-workspace/commit/1bb1ced53820127204aa7adf57510c1cbce55e12) ([#2524](https://github.com/tauri-apps/plugins-workspace/pull/2524) by [@elwerene](https://github.com/tauri-apps/plugins-workspace/../../elwerene)) enable TargetKind::LogDir on mobile
|
||||||
|
|
||||||
|
## \[2.3.0]
|
||||||
|
|
||||||
|
### feat
|
||||||
|
|
||||||
|
- [`02481501`](https://github.com/tauri-apps/plugins-workspace/commit/024815018fbc63a37afc716796a454925aa7d25e) ([#2377](https://github.com/tauri-apps/plugins-workspace/pull/2377) by [@3lpsy](https://github.com/tauri-apps/plugins-workspace/../../3lpsy)) Add a `is_skip_logger` flag to the Log Plugin `Builder` struct, a `skip_logger()` method to the Builder, and logic to avoid acquiring (creating) a logger and attaching it to the global logger. Since acquire_logger is pub, a `LoggerNotInitialized` is added and returned if it's called when the `is_skip_looger` flag is set. Overall, this feature permits a user to avoid calling `attach_logger` which can only be called once in a program's lifetime and allows the user to control the logger returned from `logger()`. Additionally, it also will allow users to generate multiple Tauri Mock apps in test suites that run and parallel and have the `log` plugin attached (assuming they use `skip_logger()`).
|
||||||
|
|
||||||
|
## \[2.2.3]
|
||||||
|
|
||||||
|
- [`1a984659`](https://github.com/tauri-apps/plugins-workspace/commit/1a9846599b6a71faf330845847a30f6bf9735898) ([#2469](https://github.com/tauri-apps/plugins-workspace/pull/2469) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Update `objc2` crate to 0.6. No user facing changes.
|
||||||
|
|
||||||
|
## \[2.2.2]
|
||||||
|
|
||||||
|
- [`6b4c3917`](https://github.com/tauri-apps/plugins-workspace/commit/6b4c3917389f4bc489d03b48a837557ac0584175) ([#2401](https://github.com/tauri-apps/plugins-workspace/pull/2401) by [@Seishiin](https://github.com/tauri-apps/plugins-workspace/../../Seishiin)) Fix timezone_strategy overwriting previously set LogLevels.
|
||||||
|
|
||||||
|
## \[2.2.1]
|
||||||
|
|
||||||
|
- [`784a54a3`](https://github.com/tauri-apps/plugins-workspace/commit/784a54a39094dfbaaa8dd123eb083c04dc6c3bb2) ([#2344](https://github.com/tauri-apps/plugins-workspace/pull/2344) by [@madsmtm](https://github.com/tauri-apps/plugins-workspace/../../madsmtm)) Use `objc2` instead of `objc`.
|
||||||
|
|
||||||
## \[2.2.0]
|
## \[2.2.0]
|
||||||
|
|
||||||
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-log"
|
name = "tauri-plugin-log"
|
||||||
version = "2.2.0"
|
version = "2.3.1"
|
||||||
description = "Configurable logging for your Tauri app."
|
description = "Configurable logging for your Tauri app."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
@@ -17,8 +17,8 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
windows = { level = "full", notes = "" }
|
windows = { level = "full", notes = "" }
|
||||||
linux = { level = "full", notes = "" }
|
linux = { level = "full", notes = "" }
|
||||||
macos = { level = "full", notes = "" }
|
macos = { level = "full", notes = "" }
|
||||||
android = { level = "unknown", notes = "" }
|
android = { level = "full", notes = "" }
|
||||||
ios = { level = "unknown", notes = "" }
|
ios = { level = "full", notes = "" }
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tauri-plugin = { workspace = true, features = ["build"] }
|
tauri-plugin = { workspace = true, features = ["build"] }
|
||||||
@@ -35,12 +35,15 @@ time = { version = "0.3", features = ["formatting", "local-offset"] }
|
|||||||
fern = "0.7"
|
fern = "0.7"
|
||||||
|
|
||||||
[target."cfg(target_os = \"android\")".dependencies]
|
[target."cfg(target_os = \"android\")".dependencies]
|
||||||
android_logger = "0.14"
|
android_logger = "0.15"
|
||||||
|
|
||||||
[target."cfg(target_os = \"ios\")".dependencies]
|
[target."cfg(target_os = \"ios\")".dependencies]
|
||||||
swift-rs = "1"
|
swift-rs = "1"
|
||||||
objc = "0.2"
|
objc2 = "0.6"
|
||||||
cocoa = "0.26"
|
objc2-foundation = { version = "0.3", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"NSString",
|
||||||
|
] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
colored = ["fern/colored"]
|
colored = ["fern/colored"]
|
||||||
|
|||||||
+17
-1
@@ -54,7 +54,23 @@ yarn add https://github.com/tauri-apps/tauri-plugin-log#v2
|
|||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
|
|
||||||
First you need to register the core plugin with Tauri:
|
First, you should enable the `log:default` capability:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"$schema": "../gen/schemas/desktop-schema.json",
|
||||||
|
"identifier": "default",
|
||||||
|
"description": "Capability for the main window",
|
||||||
|
"windows": ["main"],
|
||||||
|
"permissions": [
|
||||||
|
"core:default",
|
||||||
|
"opener:default",
|
||||||
|
"log:default" # add this!
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Then, you need to register the core plugin with Tauri:
|
||||||
|
|
||||||
`src-tauri/src/lib.rs`
|
`src-tauri/src/lib.rs`
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-log",
|
"name": "@tauri-apps/plugin-log",
|
||||||
"version": "2.2.0",
|
"version": "2.3.1",
|
||||||
"description": "Configurable logging for your Tauri app.",
|
"description": "Configurable logging for your Tauri app.",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
+47
-46
@@ -35,31 +35,6 @@ pub const WEBVIEW_TARGET: &str = "webview";
|
|||||||
|
|
||||||
#[cfg(target_os = "ios")]
|
#[cfg(target_os = "ios")]
|
||||||
mod ios {
|
mod ios {
|
||||||
use cocoa::base::id;
|
|
||||||
use objc::*;
|
|
||||||
|
|
||||||
const UTF8_ENCODING: usize = 4;
|
|
||||||
pub struct NSString(pub id);
|
|
||||||
|
|
||||||
impl NSString {
|
|
||||||
pub fn new(s: &str) -> Self {
|
|
||||||
// Safety: objc runtime calls are unsafe
|
|
||||||
NSString(unsafe {
|
|
||||||
let ns_string: id = msg_send![class!(NSString), alloc];
|
|
||||||
let ns_string: id = msg_send![ns_string,
|
|
||||||
initWithBytes:s.as_ptr()
|
|
||||||
length:s.len()
|
|
||||||
encoding:UTF8_ENCODING];
|
|
||||||
|
|
||||||
// The thing is allocated in rust, the thing must be set to autorelease in rust to relinquish control
|
|
||||||
// or it can not be released correctly in OC runtime
|
|
||||||
let _: () = msg_send![ns_string, autorelease];
|
|
||||||
|
|
||||||
ns_string
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
swift_rs::swift!(pub fn tauri_log(
|
swift_rs::swift!(pub fn tauri_log(
|
||||||
level: u8, message: *const std::ffi::c_void
|
level: u8, message: *const std::ffi::c_void
|
||||||
));
|
));
|
||||||
@@ -83,6 +58,8 @@ pub enum Error {
|
|||||||
TimeFormat(#[from] time::error::Format),
|
TimeFormat(#[from] time::error::Format),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
InvalidFormatDescription(#[from] time::error::InvalidFormatDescription),
|
InvalidFormatDescription(#[from] time::error::InvalidFormatDescription),
|
||||||
|
#[error("Internal logger disabled and cannot be acquired or attached")]
|
||||||
|
LoggerNotInitialized,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An enum representing the available verbosity levels of the logger.
|
/// An enum representing the available verbosity levels of the logger.
|
||||||
@@ -182,11 +159,12 @@ pub enum TargetKind {
|
|||||||
///
|
///
|
||||||
/// ### Platform-specific
|
/// ### Platform-specific
|
||||||
///
|
///
|
||||||
/// |Platform | Value | Example |
|
/// |Platform | Value | Example |
|
||||||
/// | ------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
/// | --------- | ----------------------------------------------------------------------------------------- | ----------------------------------------------------------- |
|
||||||
/// | Linux | `$XDG_DATA_HOME/{bundleIdentifier}/logs` or `$HOME/.local/share/{bundleIdentifier}/logs` | `/home/alice/.local/share/com.tauri.dev/logs` |
|
/// | Linux | `$XDG_DATA_HOME/{bundleIdentifier}/logs` or `$HOME/.local/share/{bundleIdentifier}/logs` | `/home/alice/.local/share/com.tauri.dev/logs` |
|
||||||
/// | macOS | `{homeDir}/Library/Logs/{bundleIdentifier}` | `/Users/Alice/Library/Logs/com.tauri.dev` |
|
/// | macOS/iOS | `{homeDir}/Library/Logs/{bundleIdentifier}` | `/Users/Alice/Library/Logs/com.tauri.dev` |
|
||||||
/// | Windows | `{FOLDERID_LocalAppData}/{bundleIdentifier}/logs` | `C:\Users\Alice\AppData\Local\com.tauri.dev\logs` |
|
/// | Windows | `{FOLDERID_LocalAppData}/{bundleIdentifier}/logs` | `C:\Users\Alice\AppData\Local\com.tauri.dev\logs` |
|
||||||
|
/// | Android | `{ConfigDir}/logs` | `/data/data/com.tauri.dev/files/logs` |
|
||||||
LogDir { file_name: Option<String> },
|
LogDir { file_name: Option<String> },
|
||||||
/// Forward logs to the webview (via the `log://log` event).
|
/// Forward logs to the webview (via the `log://log` event).
|
||||||
///
|
///
|
||||||
@@ -255,6 +233,7 @@ pub struct Builder {
|
|||||||
timezone_strategy: TimezoneStrategy,
|
timezone_strategy: TimezoneStrategy,
|
||||||
max_file_size: u128,
|
max_file_size: u128,
|
||||||
targets: Vec<Target>,
|
targets: Vec<Target>,
|
||||||
|
is_skip_logger: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Builder {
|
impl Default for Builder {
|
||||||
@@ -283,6 +262,7 @@ impl Default for Builder {
|
|||||||
timezone_strategy: DEFAULT_TIMEZONE_STRATEGY,
|
timezone_strategy: DEFAULT_TIMEZONE_STRATEGY,
|
||||||
max_file_size: DEFAULT_MAX_FILE_SIZE,
|
max_file_size: DEFAULT_MAX_FILE_SIZE,
|
||||||
targets: DEFAULT_LOG_TARGETS.into(),
|
targets: DEFAULT_LOG_TARGETS.into(),
|
||||||
|
is_skip_logger: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -303,7 +283,7 @@ impl Builder {
|
|||||||
let format =
|
let format =
|
||||||
time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]")
|
time::format_description::parse("[[[year]-[month]-[day]][[[hour]:[minute]:[second]]")
|
||||||
.unwrap();
|
.unwrap();
|
||||||
self.dispatch = fern::Dispatch::new().format(move |out, message, record| {
|
self.dispatch = self.dispatch.format(move |out, message, record| {
|
||||||
out.finish(format_args!(
|
out.finish(format_args!(
|
||||||
"{}[{}][{}] {}",
|
"{}[{}][{}] {}",
|
||||||
timezone_strategy.get_now().format(&format).unwrap(),
|
timezone_strategy.get_now().format(&format).unwrap(),
|
||||||
@@ -364,6 +344,22 @@ impl Builder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Skip the creation and global registration of a logger
|
||||||
|
///
|
||||||
|
/// If you wish to use your own global logger, you must call `skip_logger` so that the plugin does not attempt to set a second global logger. In this configuration, no logger will be created and the plugin's `log` command will rely on the result of `log::logger()`. You will be responsible for configuring the logger yourself and any included targets will be ignored. This can also be used with `tracing-log` or if running tests in parallel that require the plugin to be registered.
|
||||||
|
/// ```rust
|
||||||
|
/// static LOGGER: SimpleLogger = SimpleLogger;
|
||||||
|
///
|
||||||
|
/// log::set_logger(&SimpleLogger)?;
|
||||||
|
/// log::set_max_level(LevelFilter::Info);
|
||||||
|
/// tauri_plugin_log::Builder::new()
|
||||||
|
/// .skip_logger();
|
||||||
|
/// ```
|
||||||
|
pub fn skip_logger(mut self) -> Self {
|
||||||
|
self.is_skip_logger = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Adds a collection of targets to the logger.
|
/// Adds a collection of targets to the logger.
|
||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
@@ -429,7 +425,12 @@ impl Builder {
|
|||||||
log::Level::Info => 2,
|
log::Level::Info => 2,
|
||||||
log::Level::Warn | log::Level::Error => 3,
|
log::Level::Warn | log::Level::Error => 3,
|
||||||
},
|
},
|
||||||
ios::NSString::new(message.as_str()).0 as _,
|
// The string is allocated in rust, so we must
|
||||||
|
// autorelease it rust to give it to the Swift
|
||||||
|
// runtime.
|
||||||
|
objc2::rc::Retained::autorelease_ptr(
|
||||||
|
objc2_foundation::NSString::from_str(message.as_str()),
|
||||||
|
) as _,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
@@ -451,9 +452,6 @@ impl Builder {
|
|||||||
)?)?
|
)?)?
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
#[cfg(mobile)]
|
|
||||||
TargetKind::LogDir { .. } => continue,
|
|
||||||
#[cfg(desktop)]
|
|
||||||
TargetKind::LogDir { file_name } => {
|
TargetKind::LogDir { file_name } => {
|
||||||
let path = app_handle.path().app_log_dir()?;
|
let path = app_handle.path().app_log_dir()?;
|
||||||
if !path.exists() {
|
if !path.exists() {
|
||||||
@@ -501,6 +499,9 @@ impl Builder {
|
|||||||
self,
|
self,
|
||||||
app_handle: &AppHandle<R>,
|
app_handle: &AppHandle<R>,
|
||||||
) -> Result<(TauriPlugin<R>, log::LevelFilter, Box<dyn log::Log>), Error> {
|
) -> Result<(TauriPlugin<R>, log::LevelFilter, Box<dyn log::Log>), Error> {
|
||||||
|
if self.is_skip_logger {
|
||||||
|
return Err(Error::LoggerNotInitialized);
|
||||||
|
}
|
||||||
let plugin = Self::plugin_builder();
|
let plugin = Self::plugin_builder();
|
||||||
let (max_level, log) = Self::acquire_logger(
|
let (max_level, log) = Self::acquire_logger(
|
||||||
app_handle,
|
app_handle,
|
||||||
@@ -517,17 +518,17 @@ impl Builder {
|
|||||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||||
Self::plugin_builder()
|
Self::plugin_builder()
|
||||||
.setup(move |app_handle, _api| {
|
.setup(move |app_handle, _api| {
|
||||||
let (max_level, log) = Self::acquire_logger(
|
if !self.is_skip_logger {
|
||||||
app_handle,
|
let (max_level, log) = Self::acquire_logger(
|
||||||
self.dispatch,
|
app_handle,
|
||||||
self.rotation_strategy,
|
self.dispatch,
|
||||||
self.timezone_strategy,
|
self.rotation_strategy,
|
||||||
self.max_file_size,
|
self.timezone_strategy,
|
||||||
self.targets,
|
self.max_file_size,
|
||||||
)?;
|
self.targets,
|
||||||
|
)?;
|
||||||
attach_logger(max_level, log)?;
|
attach_logger(max_level, log)?;
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
.build()
|
.build()
|
||||||
|
|||||||
@@ -181,8 +181,8 @@ function encodeURI(uri: string): number[] {
|
|||||||
|
|
||||||
protocols.slice(1).forEach(function (protocol) {
|
protocols.slice(1).forEach(function (protocol) {
|
||||||
if (
|
if (
|
||||||
(prefix.length === 0 || prefix === 'urn:') &&
|
(prefix.length === 0 || prefix === 'urn:')
|
||||||
uri.indexOf(protocol) === 0
|
&& uri.indexOf(protocol) === 0
|
||||||
) {
|
) {
|
||||||
prefix = protocol
|
prefix = protocol
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.2]
|
||||||
|
|
||||||
|
- [`a1b3fa27`](https://github.com/tauri-apps/plugins-workspace/commit/a1b3fa27f11022c9b6622b4fab12d93239eb05de) ([#2515](https://github.com/tauri-apps/plugins-workspace/pull/2515) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Re-exported the `Geolocation`, `Haptics`, `Notification`, and `Os` structs so that they show up on docs.rs.
|
||||||
|
|
||||||
## \[2.2.1]
|
## \[2.2.1]
|
||||||
|
|
||||||
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-notification"
|
name = "tauri-plugin-notification"
|
||||||
version = "2.2.1"
|
version = "2.2.2"
|
||||||
description = "Send desktop and mobile notifications on your Tauri application."
|
description = "Send desktop and mobile notifications on your Tauri application."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -46,7 +46,7 @@ windows-version = { version = "0.1", optional = true }
|
|||||||
notify-rust = "4.11"
|
notify-rust = "4.11"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
color-backtrace = "0.6"
|
color-backtrace = "0.7"
|
||||||
ctor = "0.2"
|
ctor = "0.2"
|
||||||
maplit = "1"
|
maplit = "1"
|
||||||
|
|
||||||
|
|||||||
@@ -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,a){if("function"==typeof t||!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,a,o;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class s{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,e.set(this,(()=>{})),a.set(this,0),o.set(this,[]),this.id=function(i,t=!1){return window.__TAURI_INTERNALS__.transformCallback(i,t)}((({message:i,id:r})=>{if(r==t(this,a,"f"))for(t(this,e,"f").call(this,i),n(this,a,t(this,a,"f")+1);t(this,a,"f")in t(this,o,"f");){const i=t(this,o,"f")[t(this,a,"f")];t(this,e,"f").call(this,i),delete t(this,o,"f")[t(this,a,"f")],n(this,a,t(this,a,"f")+1)}else t(this,o,"f")[r]=i}))}set onmessage(i){n(this,e,i)}get onmessage(){return t(this,e,"f")}[(e=new WeakMap,a=new WeakMap,o=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}class c{constructor(i,t,n){this.plugin=i,this.event=t,this.channelId=n}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function l(i,t,n){const e=new s;return e.onmessage=n,u(`plugin:${i}|registerListener`,{event:t,handler:e}).then((()=>new c(i,t,e.id)))}async function u(i,t={},n){return window.__TAURI_INTERNALS__.invoke(i,t,n)}var f,h,d;i.ScheduleEvery=void 0,(f=i.ScheduleEvery||(i.ScheduleEvery={})).Year="year",f.Month="month",f.TwoWeeks="twoWeeks",f.Week="week",f.Day="day",f.Hour="hour",f.Minute="minute",f.Second="second";return i.Importance=void 0,(h=i.Importance||(i.Importance={}))[h.None=0]="None",h[h.Min=1]="Min",h[h.Low=2]="Low",h[h.Default=3]="Default",h[h.High=4]="High",i.Visibility=void 0,(d=i.Visibility||(i.Visibility={}))[d.Secret=-1]="Secret",d[d.Private=0]="Private",d[d.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 u("plugin:notification|get_active")},i.cancel=async function(i){await u("plugin:notification|cancel",{notifications:i})},i.cancelAll=async function(){await u("plugin:notification|cancel")},i.channels=async function(){return await u("plugin:notification|listChannels")},i.createChannel=async function(i){await u("plugin:notification|create_channel",{...i})},i.isPermissionGranted=async function(){return"default"!==window.Notification.permission?await Promise.resolve("granted"===window.Notification.permission):await u("plugin:notification|is_permission_granted")},i.onAction=async function(i){return await l("notification","actionPerformed",i)},i.onNotificationReceived=async function(i){return await l("notification","notification",i)},i.pending=async function(){return await u("plugin:notification|get_pending")},i.registerActionTypes=async function(i){await u("plugin:notification|register_action_types",{types:i})},i.removeActive=async function(i){await u("plugin:notification|remove_active",{notifications:i})},i.removeAllActive=async function(){await u("plugin:notification|remove_active")},i.removeChannel=async function(i){await u("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 n(i,n,t,e){if("function"==typeof n||!n.has(i))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===t?e:"a"===t?e.call(i):e?e.value:n.get(i)}function t(i,n,t,e,o){if("function"==typeof n||!n.has(i))throw new TypeError("Cannot write private member to an object whose class did not declare it");return n.set(i,t),t}var e,o,a;"function"==typeof SuppressedError&&SuppressedError;const r="__TAURI_TO_IPC_KEY__";class c{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,e.set(this,(()=>{})),o.set(this,0),a.set(this,[]),this.id=function(i,n=!1){return window.__TAURI_INTERNALS__.transformCallback(i,n)}((({message:i,id:r})=>{if(r==n(this,o,"f"))for(n(this,e,"f").call(this,i),t(this,o,n(this,o,"f")+1);n(this,o,"f")in n(this,a,"f");){const i=n(this,a,"f")[n(this,o,"f")];n(this,e,"f").call(this,i),delete n(this,a,"f")[n(this,o,"f")],t(this,o,n(this,o,"f")+1)}else n(this,a,"f")[r]=i}))}set onmessage(i){t(this,e,i)}get onmessage(){return n(this,e,"f")}[(e=new WeakMap,o=new WeakMap,a=new WeakMap,r)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[r]()}}class s{constructor(i,n,t){this.plugin=i,this.event=n,this.channelId=t}async unregister(){return u(`plugin:${this.plugin}|remove_listener`,{event:this.event,channelId:this.channelId})}}async function l(i,n,t){const e=new c;return e.onmessage=t,u(`plugin:${i}|registerListener`,{event:n,handler:e}).then((()=>new s(i,n,e.id)))}async function u(i,n={},t){return window.__TAURI_INTERNALS__.invoke(i,n,t)}var f,h,d;i.ScheduleEvery=void 0,(f=i.ScheduleEvery||(i.ScheduleEvery={})).Year="year",f.Month="month",f.TwoWeeks="twoWeeks",f.Week="week",f.Day="day",f.Hour="hour",f.Minute="minute",f.Second="second";return i.Importance=void 0,(h=i.Importance||(i.Importance={}))[h.None=0]="None",h[h.Min=1]="Min",h[h.Low=2]="Low",h[h.Default=3]="Default",h[h.High=4]="High",i.Visibility=void 0,(d=i.Visibility||(i.Visibility={}))[d.Secret=-1]="Secret",d[d.Private=0]="Private",d[d.Public=1]="Public",i.Schedule=class{static at(i,n=!1,t=!1){return{at:{date:i,repeating:n,allowWhileIdle:t},interval:void 0,every:void 0}}static interval(i,n=!1){return{at:void 0,interval:{interval:i,allowWhileIdle:n},every:void 0}}static every(i,n,t=!1){return{at:void 0,interval:void 0,every:{interval:i,count:n,allowWhileIdle:t}}}},i.active=async function(){return await u("plugin:notification|get_active")},i.cancel=async function(i){await u("plugin:notification|cancel",{notifications:i})},i.cancelAll=async function(){await u("plugin:notification|cancel")},i.channels=async function(){return await u("plugin:notification|listChannels")},i.createChannel=async function(i){await u("plugin:notification|create_channel",{...i})},i.isPermissionGranted=async function(){return"default"!==window.Notification.permission?await Promise.resolve("granted"===window.Notification.permission):await u("plugin:notification|is_permission_granted")},i.onAction=async function(i){return await l("notification","actionPerformed",i)},i.onNotificationReceived=async function(i){return await l("notification","notification",i)},i.pending=async function(){return await u("plugin:notification|get_pending")},i.registerActionTypes=async function(i){await u("plugin:notification|register_action_types",{types:i})},i.removeActive=async function(i){await u("plugin:notification|remove_active",{notifications:i})},i.removeAllActive=async function(){await u("plugin:notification|remove_active")},i.removeChannel=async function(i){await u("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,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-notification",
|
"name": "@tauri-apps/plugin-notification",
|
||||||
"version": "2.2.1",
|
"version": "2.2.2",
|
||||||
"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"
|
||||||
|
|||||||
@@ -18,6 +18,8 @@ pub fn init<R: Runtime, C: DeserializeOwned>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Access to the notification APIs.
|
/// Access to the notification APIs.
|
||||||
|
///
|
||||||
|
/// You can get an instance of this type via [`NotificationExt`](crate::NotificationExt)
|
||||||
pub struct Notification<R: Runtime>(AppHandle<R>);
|
pub struct Notification<R: Runtime>(AppHandle<R>);
|
||||||
|
|
||||||
impl<R: Runtime> crate::NotificationBuilder<R> {
|
impl<R: Runtime> crate::NotificationBuilder<R> {
|
||||||
|
|||||||
@@ -34,9 +34,9 @@ mod models;
|
|||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
|
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
use desktop::Notification;
|
pub use desktop::Notification;
|
||||||
#[cfg(mobile)]
|
#[cfg(mobile)]
|
||||||
use mobile::Notification;
|
pub use mobile::Notification;
|
||||||
|
|
||||||
/// The notification builder.
|
/// The notification builder.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -120,7 +120,7 @@ impl<R: Runtime> NotificationBuilder<R> {
|
|||||||
|
|
||||||
/// Identifier used to group multiple notifications.
|
/// Identifier used to group multiple notifications.
|
||||||
///
|
///
|
||||||
/// https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent/1649872-threadidentifier
|
/// <https://developer.apple.com/documentation/usernotifications/unmutablenotificationcontent/1649872-threadidentifier>
|
||||||
pub fn group(mut self, group: impl Into<String>) -> Self {
|
pub fn group(mut self, group: impl Into<String>) -> Self {
|
||||||
self.data.group.replace(group.into());
|
self.data.group.replace(group.into());
|
||||||
self
|
self
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ impl<R: Runtime> crate::NotificationBuilder<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Access to the notification APIs.
|
/// Access to the notification APIs.
|
||||||
|
///
|
||||||
|
/// You can get an instance of this type via [`NotificationExt`](crate::NotificationExt)
|
||||||
pub struct Notification<R: Runtime>(PluginHandle<R>);
|
pub struct Notification<R: Runtime>(PluginHandle<R>);
|
||||||
|
|
||||||
impl<R: Runtime> Notification<R> {
|
impl<R: Runtime> Notification<R> {
|
||||||
|
|||||||
@@ -1,5 +1,14 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.6]
|
||||||
|
|
||||||
|
- [`1a984659`](https://github.com/tauri-apps/plugins-workspace/commit/1a9846599b6a71faf330845847a30f6bf9735898) ([#2469](https://github.com/tauri-apps/plugins-workspace/pull/2469) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Update `objc2` crate to 0.6. No user facing changes.
|
||||||
|
- [`71f95c9f`](https://github.com/tauri-apps/plugins-workspace/commit/71f95c9f05b29cf1be586849614c0b007757c15d) ([#2445](https://github.com/tauri-apps/plugins-workspace/pull/2445) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `windows` crate to 0.60 to match Tauri 2.3.0. No user facing changes.
|
||||||
|
|
||||||
|
## \[2.2.5]
|
||||||
|
|
||||||
|
- [`5b821181`](https://github.com/tauri-apps/plugins-workspace/commit/5b8211815825ddae2dcc0c00520e0cfdff002763) ([#2332](https://github.com/tauri-apps/plugins-workspace/pull/2332) by [@betamos](https://github.com/tauri-apps/plugins-workspace/../../betamos)) Fix broken JS commands `opener.openPath` and `opener.openUrl` on mobile.
|
||||||
|
|
||||||
## \[2.2.4]
|
## \[2.2.4]
|
||||||
|
|
||||||
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-opener"
|
name = "tauri-plugin-opener"
|
||||||
version = "2.2.4"
|
version = "2.2.6"
|
||||||
description = "Open files and URLs using their default application."
|
description = "Open files and URLs using their default application."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -15,7 +15,7 @@ rustdoc-args = ["--cfg", "docsrs"]
|
|||||||
# Platforms supported by the plugin
|
# Platforms supported by the plugin
|
||||||
# Support levels are "full", "partial", "none", "unknown"
|
# Support levels are "full", "partial", "none", "unknown"
|
||||||
# Details of the support level are left to plugin maintainer
|
# Details of the support level are left to plugin maintainer
|
||||||
[package.metadata.platforms]
|
[package.metadata.platforms.support]
|
||||||
windows = { level = "full", notes = "" }
|
windows = { level = "full", notes = "" }
|
||||||
linux = { level = "full", notes = "" }
|
linux = { level = "full", notes = "" }
|
||||||
macos = { level = "full", notes = "" }
|
macos = { level = "full", notes = "" }
|
||||||
@@ -40,7 +40,7 @@ glob = { workspace = true }
|
|||||||
dunce = { workspace = true }
|
dunce = { workspace = true }
|
||||||
|
|
||||||
[target."cfg(windows)".dependencies.windows]
|
[target."cfg(windows)".dependencies.windows]
|
||||||
version = "0.58"
|
version = "0.60"
|
||||||
features = [
|
features = [
|
||||||
"Win32_Foundation",
|
"Win32_Foundation",
|
||||||
"Win32_UI_Shell_Common",
|
"Win32_UI_Shell_Common",
|
||||||
@@ -54,12 +54,14 @@ zbus = { workspace = true }
|
|||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
|
||||||
[target."cfg(target_os = \"macos\")".dependencies.objc2-app-kit]
|
[target."cfg(target_os = \"macos\")".dependencies.objc2-app-kit]
|
||||||
version = "0.2"
|
version = "0.3"
|
||||||
features = ["NSWorkspace"]
|
default-features = false
|
||||||
|
features = ["std", "NSWorkspace"]
|
||||||
|
|
||||||
[target."cfg(target_os = \"macos\")".dependencies.objc2-foundation]
|
[target."cfg(target_os = \"macos\")".dependencies.objc2-foundation]
|
||||||
version = "0.2"
|
version = "0.3"
|
||||||
features = ["NSURL", "NSArray", "NSString"]
|
default-features = false
|
||||||
|
features = ["std", "NSURL", "NSArray", "NSString"]
|
||||||
|
|
||||||
[target.'cfg(target_os = "ios")'.dependencies]
|
[target.'cfg(target_os = "ios")'.dependencies]
|
||||||
tauri = { workspace = true, features = ["wry"] }
|
tauri = { workspace = true, features = ["wry"] }
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ window.addEventListener('click', function (evt) {
|
|||||||
// return early if
|
// return early if
|
||||||
if (
|
if (
|
||||||
// event was prevented
|
// event was prevented
|
||||||
evt.defaultPrevented ||
|
evt.defaultPrevented
|
||||||
// or not a left click
|
// or not a left click
|
||||||
evt.button !== 0 ||
|
|| evt.button !== 0
|
||||||
// or meta key pressed
|
// or meta key pressed
|
||||||
evt.metaKey ||
|
|| evt.metaKey
|
||||||
// or al key pressed
|
// or al key pressed
|
||||||
evt.altKey
|
|| evt.altKey
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
@@ -28,16 +28,16 @@ window.addEventListener('click', function (evt) {
|
|||||||
// return early if
|
// return early if
|
||||||
if (
|
if (
|
||||||
// not tirggered from <a> element
|
// not tirggered from <a> element
|
||||||
!a ||
|
!a
|
||||||
// or doesn't have a href
|
// or doesn't have a href
|
||||||
!a.href ||
|
|| !a.href
|
||||||
// or not supposed to be open in a new tab
|
// or not supposed to be open in a new tab
|
||||||
!(
|
|| !(
|
||||||
a.target === '_blank' ||
|
a.target === '_blank'
|
||||||
// or ctrl key pressed
|
// or ctrl key pressed
|
||||||
evt.ctrlKey ||
|
|| evt.ctrlKey
|
||||||
// or shift key pressed
|
// or shift key pressed
|
||||||
evt.shiftKey
|
|| evt.shiftKey
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
@@ -47,9 +47,9 @@ window.addEventListener('click', function (evt) {
|
|||||||
// return early if
|
// return early if
|
||||||
if (
|
if (
|
||||||
// same origin (internal navigation)
|
// same origin (internal navigation)
|
||||||
url.origin === window.location.origin ||
|
url.origin === window.location.origin
|
||||||
// not default protocols
|
// not default protocols
|
||||||
['http:', 'https:', 'mailto:', 'tel:'].every((p) => url.protocol !== p)
|
|| ['http:', 'https:', 'mailto:', 'tel:'].every((p) => url.protocol !== p)
|
||||||
)
|
)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-opener",
|
"name": "@tauri-apps/plugin-opener",
|
||||||
"version": "2.2.4",
|
"version": "2.2.6",
|
||||||
"description": "Open files and URLs using their default application.",
|
"description": "Open files and URLs using their default application.",
|
||||||
"license": "MIT OR Apache-2.0",
|
"license": "MIT OR Apache-2.0",
|
||||||
"authors": [
|
"authors": [
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ use tauri::{
|
|||||||
AppHandle, Runtime,
|
AppHandle, Runtime,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{scope::Scope, Error};
|
use crate::{scope::Scope, Error, OpenerExt};
|
||||||
|
|
||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn open_url<R: Runtime>(
|
pub async fn open_url<R: Runtime>(
|
||||||
@@ -34,7 +34,7 @@ pub async fn open_url<R: Runtime>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if scope.is_url_allowed(&url, with.as_deref()) {
|
if scope.is_url_allowed(&url, with.as_deref()) {
|
||||||
crate::open_url(url, with)
|
app.opener().open_url(url, with)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ForbiddenUrl { url, with })
|
Err(Error::ForbiddenUrl { url, with })
|
||||||
}
|
}
|
||||||
@@ -63,7 +63,7 @@ pub async fn open_path<R: Runtime>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
if scope.is_path_allowed(Path::new(&path), with.as_deref())? {
|
if scope.is_path_allowed(Path::new(&path), with.as_deref())? {
|
||||||
crate::open_path(path, with)
|
app.opener().open_path(path, with)
|
||||||
} else {
|
} else {
|
||||||
Err(Error::ForbiddenPath { path, with })
|
Err(Error::ForbiddenPath { path, with })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ impl<R: Runtime> Opener<R> {
|
|||||||
/// - **Android / iOS**: Always opens using default program.
|
/// - **Android / iOS**: Always opens using default program.
|
||||||
#[cfg(desktop)]
|
#[cfg(desktop)]
|
||||||
pub fn open_url(&self, url: impl Into<String>, with: Option<impl Into<String>>) -> Result<()> {
|
pub fn open_url(&self, url: impl Into<String>, with: Option<impl Into<String>>) -> Result<()> {
|
||||||
crate::open::open(url.into(), with.map(Into::into)).map_err(Into::into)
|
crate::open::open(url.into(), with.map(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a url with a default or specific program.
|
/// Open a url with a default or specific program.
|
||||||
@@ -108,7 +108,7 @@ impl<R: Runtime> Opener<R> {
|
|||||||
path: impl Into<String>,
|
path: impl Into<String>,
|
||||||
with: Option<impl Into<String>>,
|
with: Option<impl Into<String>>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
crate::open::open(path.into(), with.map(Into::into)).map_err(Into::into)
|
crate::open::open(path.into(), with.map(Into::into))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a path with a default or specific program.
|
/// Open a path with a default or specific program.
|
||||||
|
|||||||
@@ -185,7 +185,7 @@ mod imp {
|
|||||||
let path = path.to_string_lossy();
|
let path = path.to_string_lossy();
|
||||||
let path = NSString::from_str(&path);
|
let path = NSString::from_str(&path);
|
||||||
let urls = vec![NSURL::fileURLWithPath(&path)];
|
let urls = vec![NSURL::fileURLWithPath(&path)];
|
||||||
let urls = NSArray::from_vec(urls);
|
let urls = NSArray::from_retained_slice(&urls);
|
||||||
|
|
||||||
let workspace = NSWorkspace::new();
|
let workspace = NSWorkspace::new();
|
||||||
workspace.activateFileViewerSelectingURLs(&urls);
|
workspace.activateFileViewerSelectingURLs(&urls);
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.1]
|
||||||
|
|
||||||
|
- [`a1b3fa27`](https://github.com/tauri-apps/plugins-workspace/commit/a1b3fa27f11022c9b6622b4fab12d93239eb05de) ([#2515](https://github.com/tauri-apps/plugins-workspace/pull/2515) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Re-exported the `Geolocation`, `Haptics`, `Notification`, and `Os` structs so that they show up on docs.rs.
|
||||||
|
|
||||||
## \[2.2.0]
|
## \[2.2.0]
|
||||||
|
|
||||||
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
- [`3a79266b`](https://github.com/tauri-apps/plugins-workspace/commit/3a79266b8cf96a55b1ae6339d725567d45a44b1d) ([#2173](https://github.com/tauri-apps/plugins-workspace/pull/2173) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Bumped all plugins to `v2.2.0`. From now, the versions for the Rust and JavaScript packages of each plugin will be in sync with each other.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-os"
|
name = "tauri-plugin-os"
|
||||||
version = "2.2.0"
|
version = "2.2.1"
|
||||||
description = "Read information about the operating system."
|
description = "Read information about the operating system."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -31,5 +31,5 @@ log = { workspace = true }
|
|||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
os_info = "3"
|
os_info = "3"
|
||||||
sys-locale = "0.3"
|
sys-locale = "0.3"
|
||||||
gethostname = "0.5"
|
gethostname = "1.0"
|
||||||
serialize-to-javascript = "=0.1.1"
|
serialize-to-javascript = "=0.1.1"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-os",
|
"name": "@tauri-apps/plugin-os",
|
||||||
"version": "2.2.0",
|
"version": "2.2.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"
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ pub fn exe_extension() -> &'static str {
|
|||||||
std::env::consts::EXE_EXTENSION
|
std::env::consts::EXE_EXTENSION
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the current operating system locale with the `BCP-47` language tag. If the locale couldn’t be obtained, `None` is returned instead.
|
/// Returns the current operating system locale with the `BCP-47` language tag. If the locale couldn't be obtained, `None` is returned instead.
|
||||||
pub fn locale() -> Option<String> {
|
pub fn locale() -> Option<String> {
|
||||||
sys_locale::get_locale()
|
sys_locale::get_locale()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
## Default Permission
|
## Default Permission
|
||||||
|
|
||||||
This permission set configures which
|
This permission set configures which
|
||||||
process feeatures are by default exposed.
|
process features are by default exposed.
|
||||||
|
|
||||||
#### Granted Permissions
|
#### Granted Permissions
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
[default]
|
[default]
|
||||||
description = """
|
description = """
|
||||||
This permission set configures which
|
This permission set configures which
|
||||||
process feeatures are by default exposed.
|
process features are by default exposed.
|
||||||
|
|
||||||
#### Granted Permissions
|
#### Granted Permissions
|
||||||
|
|
||||||
|
|||||||
@@ -315,7 +315,7 @@
|
|||||||
"const": "deny-restart"
|
"const": "deny-restart"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"description": "This permission set configures which\nprocess feeatures are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n",
|
"description": "This permission set configures which\nprocess features are by default exposed.\n\n#### Granted Permissions\n\nThis enables to quit via `allow-exit` and restart via `allow-restart`\nthe application.\n",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"const": "default"
|
"const": "default"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_SHELL__=function(e){"use strict";function t(e,t,s,i){if("a"===s&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?i:"a"===s?i.call(e):i?i.value:t.get(e)}function s(e,t,s,i,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var i,n,r;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),n.set(this,0),r.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:o})=>{if(o==t(this,n,"f"))for(t(this,i,"f").call(this,e),s(this,n,t(this,n,"f")+1);t(this,n,"f")in t(this,r,"f");){const e=t(this,r,"f")[t(this,n,"f")];t(this,i,"f").call(this,e),delete t(this,r,"f")[t(this,n,"f")],s(this,n,t(this,n,"f")+1)}else t(this,r,"f")[o]=e}))}set onmessage(e){s(this,i,e)}get onmessage(){return t(this,i,"f")}[(i=new WeakMap,n=new WeakMap,r=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function h(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class c{constructor(){this.eventListeners=Object.create(null)}addListener(e,t){return this.on(e,t)}removeListener(e,t){return this.off(e,t)}on(e,t){return e in this.eventListeners?this.eventListeners[e].push(t):this.eventListeners[e]=[t],this}once(e,t){const s=i=>{this.removeListener(e,s),t(i)};return this.addListener(e,s)}off(e,t){return e in this.eventListeners&&(this.eventListeners[e]=this.eventListeners[e].filter((e=>e!==t))),this}removeAllListeners(e){return e?delete this.eventListeners[e]:this.eventListeners=Object.create(null),this}emit(e,t){if(e in this.eventListeners){const s=this.eventListeners[e];for(const e of s)e(t);return!0}return!1}listenerCount(e){return e in this.eventListeners?this.eventListeners[e].length:0}prependListener(e,t){return e in this.eventListeners?this.eventListeners[e].unshift(t):this.eventListeners[e]=[t],this}prependOnceListener(e,t){const s=i=>{this.removeListener(e,s),t(i)};return this.prependListener(e,s)}}class l{constructor(e){this.pid=e}async write(e){await h("plugin:shell|stdin_write",{pid:this.pid,buffer:e})}async kill(){await h("plugin:shell|kill",{cmd:"killChild",pid:this.pid})}}class u extends c{constructor(e,t=[],s){super(),this.stdout=new c,this.stderr=new c,this.program=e,this.args="string"==typeof t?[t]:t,this.options=s??{}}static create(e,t=[],s){return new u(e,t,s)}static sidecar(e,t=[],s){const i=new u(e,t,s);return i.options.sidecar=!0,i}async spawn(){const e=this.program,t=this.args,s=this.options;"object"==typeof t&&Object.freeze(t);const i=new a;return i.onmessage=e=>{switch(e.event){case"Error":this.emit("error",e.payload);break;case"Terminated":this.emit("close",e.payload);break;case"Stdout":this.stdout.emit("data",e.payload);break;case"Stderr":this.stderr.emit("data",e.payload)}},await h("plugin:shell|spawn",{program:e,args:t,options:s,onEvent:i}).then((e=>new l(e)))}async execute(){const e=this.program,t=this.args,s=this.options;return"object"==typeof t&&Object.freeze(t),await h("plugin:shell|execute",{program:e,args:t,options:s})}}return e.Child=l,e.Command=u,e.EventEmitter=c,e.open=async function(e,t){await h("plugin:shell|open",{path:e,with:t})},e}({});Object.defineProperty(window.__TAURI__,"shell",{value:__TAURI_PLUGIN_SHELL__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_SHELL__=function(e){"use strict";function t(e,t,s,i){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?i:"a"===s?i.call(e):i?i.value:t.get(e)}function s(e,t,s,i,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var i,n,r;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class a{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),n.set(this,0),r.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:o})=>{if(o==t(this,n,"f"))for(t(this,i,"f").call(this,e),s(this,n,t(this,n,"f")+1);t(this,n,"f")in t(this,r,"f");){const e=t(this,r,"f")[t(this,n,"f")];t(this,i,"f").call(this,e),delete t(this,r,"f")[t(this,n,"f")],s(this,n,t(this,n,"f")+1)}else t(this,r,"f")[o]=e}))}set onmessage(e){s(this,i,e)}get onmessage(){return t(this,i,"f")}[(i=new WeakMap,n=new WeakMap,r=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function h(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class c{constructor(){this.eventListeners=Object.create(null)}addListener(e,t){return this.on(e,t)}removeListener(e,t){return this.off(e,t)}on(e,t){return e in this.eventListeners?this.eventListeners[e].push(t):this.eventListeners[e]=[t],this}once(e,t){const s=i=>{this.removeListener(e,s),t(i)};return this.addListener(e,s)}off(e,t){return e in this.eventListeners&&(this.eventListeners[e]=this.eventListeners[e].filter((e=>e!==t))),this}removeAllListeners(e){return e?delete this.eventListeners[e]:this.eventListeners=Object.create(null),this}emit(e,t){if(e in this.eventListeners){const s=this.eventListeners[e];for(const e of s)e(t);return!0}return!1}listenerCount(e){return e in this.eventListeners?this.eventListeners[e].length:0}prependListener(e,t){return e in this.eventListeners?this.eventListeners[e].unshift(t):this.eventListeners[e]=[t],this}prependOnceListener(e,t){const s=i=>{this.removeListener(e,s),t(i)};return this.prependListener(e,s)}}class l{constructor(e){this.pid=e}async write(e){await h("plugin:shell|stdin_write",{pid:this.pid,buffer:e})}async kill(){await h("plugin:shell|kill",{cmd:"killChild",pid:this.pid})}}class u extends c{constructor(e,t=[],s){super(),this.stdout=new c,this.stderr=new c,this.program=e,this.args="string"==typeof t?[t]:t,this.options=s??{}}static create(e,t=[],s){return new u(e,t,s)}static sidecar(e,t=[],s){const i=new u(e,t,s);return i.options.sidecar=!0,i}async spawn(){const e=this.program,t=this.args,s=this.options;"object"==typeof t&&Object.freeze(t);const i=new a;return i.onmessage=e=>{switch(e.event){case"Error":this.emit("error",e.payload);break;case"Terminated":this.emit("close",e.payload);break;case"Stdout":this.stdout.emit("data",e.payload);break;case"Stderr":this.stderr.emit("data",e.payload)}},await h("plugin:shell|spawn",{program:e,args:t,options:s,onEvent:i}).then((e=>new l(e)))}async execute(){const e=this.program,t=this.args,s=this.options;return"object"==typeof t&&Object.freeze(t),await h("plugin:shell|execute",{program:e,args:t,options:s})}}return e.Child=l,e.Command=u,e.EventEmitter=c,e.open=async function(e,t){await h("plugin:shell|open",{path:e,with:t})},e}({});Object.defineProperty(window.__TAURI__,"shell",{value:__TAURI_PLUGIN_SHELL__})}
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ function openLinks(): void {
|
|||||||
if (target.matches('a')) {
|
if (target.matches('a')) {
|
||||||
const t = target as HTMLAnchorElement
|
const t = target as HTMLAnchorElement
|
||||||
if (
|
if (
|
||||||
t.href !== '' &&
|
t.href !== ''
|
||||||
['http://', 'https://', 'mailto:', 'tel:'].some((v) =>
|
&& ['http://', 'https://', 'mailto:', 'tel:'].some((v) =>
|
||||||
t.href.startsWith(v)
|
t.href.startsWith(v)
|
||||||
) &&
|
)
|
||||||
t.target === '_blank'
|
&& t.target === '_blank'
|
||||||
) {
|
) {
|
||||||
void invoke('plugin:shell|open', {
|
void invoke('plugin:shell|open', {
|
||||||
path: t.href
|
path: t.href
|
||||||
@@ -31,8 +31,8 @@ function openLinks(): void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
document.readyState === 'complete' ||
|
document.readyState === 'complete'
|
||||||
document.readyState === 'interactive'
|
|| document.readyState === 'interactive'
|
||||||
) {
|
) {
|
||||||
openLinks()
|
openLinks()
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ impl<R: Runtime> Shell<R> {
|
|||||||
#[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
|
#[deprecated(since = "2.1.0", note = "Use tauri-plugin-opener instead.")]
|
||||||
#[allow(deprecated)]
|
#[allow(deprecated)]
|
||||||
pub fn open(&self, path: impl Into<String>, with: Option<open::Program>) -> Result<()> {
|
pub fn open(&self, path: impl Into<String>, with: Option<open::Program>) -> Result<()> {
|
||||||
open::open(&self.open_scope, path.into(), with).map_err(Into::into)
|
open::open(&self.open_scope, path.into(), with)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a (url) path with a default or specific browser opening program.
|
/// Open a (url) path with a default or specific browser opening program.
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.2.2]
|
||||||
|
|
||||||
|
- [`1ab5f157`](https://github.com/tauri-apps/plugins-workspace/commit/1ab5f1576333174095bc7dad4bef7a8576bb29ab) ([#2452](https://github.com/tauri-apps/plugins-workspace/pull/2452) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed `null pointer dereference` panic on rust nightly on Windows.
|
||||||
|
|
||||||
## \[2.2.1]
|
## \[2.2.1]
|
||||||
|
|
||||||
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
- [`da5c59e2`](https://github.com/tauri-apps/plugins-workspace/commit/da5c59e2fe879d177e3cfd52fcacce85440423cb) ([#2271](https://github.com/tauri-apps/plugins-workspace/pull/2271) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Updated `zbus` dependency to version 5. No API changes.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-single-instance"
|
name = "tauri-plugin-single-instance"
|
||||||
version = "2.2.1"
|
version = "2.2.2"
|
||||||
description = "Ensure a single instance of your tauri app is running."
|
description = "Ensure a single instance of your tauri app is running."
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
license = { workspace = true }
|
license = { workspace = true }
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
"author": "",
|
"author": "",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "2.2.4"
|
"@tauri-apps/cli": "2.3.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,5 +3,5 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri_build::build()
|
tauri_build::build()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
max_width = 100
|
|
||||||
hard_tabs = false
|
|
||||||
tab_spaces = 2
|
|
||||||
newline_style = "Auto"
|
|
||||||
use_small_heuristics = "Default"
|
|
||||||
reorder_imports = true
|
|
||||||
reorder_modules = true
|
|
||||||
remove_nested_parens = true
|
|
||||||
edition = "2021"
|
|
||||||
merge_derives = true
|
|
||||||
use_try_shorthand = false
|
|
||||||
use_field_init_shorthand = false
|
|
||||||
force_explicit_abi = true
|
|
||||||
imports_granularity = "Crate"
|
|
||||||
@@ -3,16 +3,15 @@
|
|||||||
// SPDX-License-Identifier: MIT
|
// SPDX-License-Identifier: MIT
|
||||||
|
|
||||||
#![cfg_attr(
|
#![cfg_attr(
|
||||||
all(not(debug_assertions), target_os = "windows"),
|
all(not(debug_assertions), target_os = "windows"),
|
||||||
windows_subsystem = "windows"
|
windows_subsystem = "windows"
|
||||||
)]
|
)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
tauri::Builder::default()
|
tauri::Builder::default()
|
||||||
.plugin(tauri_plugin_cli::init())
|
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
|
||||||
.plugin(tauri_plugin_single_instance::init(|app, argv, cwd| {
|
println!("{}, {argv:?}, {cwd}", app.package_info().name);
|
||||||
println!("{}, {argv:?}, {cwd}", app.package_info().name);
|
}))
|
||||||
}))
|
.run(tauri::generate_context!())
|
||||||
.run(tauri::generate_context!())
|
.expect("error while running tauri application");
|
||||||
.expect("error while running tauri application");
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,18 +20,38 @@ use windows_sys::Win32::{
|
|||||||
},
|
},
|
||||||
UI::WindowsAndMessaging::{
|
UI::WindowsAndMessaging::{
|
||||||
self as w32wm, CreateWindowExW, DefWindowProcW, DestroyWindow, FindWindowW,
|
self as w32wm, CreateWindowExW, DefWindowProcW, DestroyWindow, FindWindowW,
|
||||||
RegisterClassExW, SendMessageW, GWL_STYLE, GWL_USERDATA, WINDOW_LONG_PTR_INDEX,
|
RegisterClassExW, SendMessageW, CREATESTRUCTW, GWLP_USERDATA, GWL_STYLE,
|
||||||
WM_COPYDATA, WM_DESTROY, WNDCLASSEXW, WS_EX_LAYERED, WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW,
|
WINDOW_LONG_PTR_INDEX, WM_COPYDATA, WM_CREATE, WM_DESTROY, WNDCLASSEXW, WS_EX_LAYERED,
|
||||||
WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
WS_EX_NOACTIVATE, WS_EX_TOOLWINDOW, WS_EX_TRANSPARENT, WS_OVERLAPPED, WS_POPUP, WS_VISIBLE,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
struct MutexHandle(isize);
|
|
||||||
struct TargetWindowHandle(isize);
|
|
||||||
|
|
||||||
const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542;
|
const WMCOPYDATA_SINGLE_INSTANCE_DATA: usize = 1542;
|
||||||
|
|
||||||
pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
struct MutexHandle(isize);
|
||||||
|
|
||||||
|
struct TargetWindowHandle(isize);
|
||||||
|
|
||||||
|
struct UserData<R: Runtime> {
|
||||||
|
app: AppHandle<R>,
|
||||||
|
callback: Box<SingleInstanceCallback<R>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: Runtime> UserData<R> {
|
||||||
|
unsafe fn from_hwnd_raw(hwnd: HWND) -> *mut Self {
|
||||||
|
GetWindowLongPtrW(hwnd, GWLP_USERDATA) as *mut Self
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe fn from_hwnd<'a>(hwnd: HWND) -> &'a mut Self {
|
||||||
|
&mut *Self::from_hwnd_raw(hwnd)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run_callback(&mut self, args: Vec<String>, cwd: String) {
|
||||||
|
(self.callback)(&self.app, args, cwd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn init<R: Runtime>(callback: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
||||||
plugin::Builder::new("single-instance")
|
plugin::Builder::new("single-instance")
|
||||||
.setup(|app, _api| {
|
.setup(|app, _api| {
|
||||||
#[allow(unused_mut)]
|
#[allow(unused_mut)]
|
||||||
@@ -54,21 +74,22 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
|||||||
let hwnd = FindWindowW(class_name.as_ptr(), window_name.as_ptr());
|
let hwnd = FindWindowW(class_name.as_ptr(), window_name.as_ptr());
|
||||||
|
|
||||||
if !hwnd.is_null() {
|
if !hwnd.is_null() {
|
||||||
let data = format!(
|
let cwd = std::env::current_dir().unwrap_or_default();
|
||||||
"{}|{}\0",
|
let cwd = cwd.to_str().unwrap_or_default();
|
||||||
std::env::current_dir()
|
|
||||||
.unwrap_or_default()
|
let args = std::env::args().collect::<Vec<String>>().join("|");
|
||||||
.to_str()
|
|
||||||
.unwrap_or_default(),
|
let data = format!("{cwd}|{args}\0",);
|
||||||
std::env::args().collect::<Vec<String>>().join("|")
|
|
||||||
);
|
|
||||||
let bytes = data.as_bytes();
|
let bytes = data.as_bytes();
|
||||||
let cds = COPYDATASTRUCT {
|
let cds = COPYDATASTRUCT {
|
||||||
dwData: WMCOPYDATA_SINGLE_INSTANCE_DATA,
|
dwData: WMCOPYDATA_SINGLE_INSTANCE_DATA,
|
||||||
cbData: bytes.len() as _,
|
cbData: bytes.len() as _,
|
||||||
lpData: bytes.as_ptr() as _,
|
lpData: bytes.as_ptr() as _,
|
||||||
};
|
};
|
||||||
|
|
||||||
SendMessageW(hwnd, WM_COPYDATA, 0, &cds as *const _ as _);
|
SendMessageW(hwnd, WM_COPYDATA, 0, &cds as *const _ as _);
|
||||||
|
|
||||||
app.cleanup_before_exit();
|
app.cleanup_before_exit();
|
||||||
std::process::exit(0);
|
std::process::exit(0);
|
||||||
}
|
}
|
||||||
@@ -76,15 +97,12 @@ pub fn init<R: Runtime>(f: Box<SingleInstanceCallback<R>>) -> TauriPlugin<R> {
|
|||||||
} else {
|
} else {
|
||||||
app.manage(MutexHandle(hmutex as _));
|
app.manage(MutexHandle(hmutex as _));
|
||||||
|
|
||||||
let hwnd = create_event_target_window::<R>(&class_name, &window_name);
|
let userdata = UserData {
|
||||||
unsafe {
|
app: app.clone(),
|
||||||
SetWindowLongPtrW(
|
callback,
|
||||||
hwnd,
|
|
||||||
GWL_USERDATA,
|
|
||||||
Box::into_raw(Box::new((app.clone(), f))) as _,
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
let userdata = Box::into_raw(Box::new(userdata));
|
||||||
|
let hwnd = create_event_target_window::<R>(&class_name, &window_name, userdata);
|
||||||
app.manage(TargetWindowHandle(hwnd as _));
|
app.manage(TargetWindowHandle(hwnd as _));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,32 +134,43 @@ unsafe extern "system" fn single_instance_window_proc<R: Runtime>(
|
|||||||
wparam: WPARAM,
|
wparam: WPARAM,
|
||||||
lparam: LPARAM,
|
lparam: LPARAM,
|
||||||
) -> LRESULT {
|
) -> LRESULT {
|
||||||
let data_ptr = GetWindowLongPtrW(hwnd, GWL_USERDATA)
|
|
||||||
as *mut (AppHandle<R>, Box<SingleInstanceCallback<R>>);
|
|
||||||
let (app_handle, callback) = &mut *data_ptr;
|
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
|
WM_CREATE => {
|
||||||
|
let create_struct = &*(lparam as *const CREATESTRUCTW);
|
||||||
|
let userdata = create_struct.lpCreateParams as *const UserData<R>;
|
||||||
|
SetWindowLongPtrW(hwnd, GWLP_USERDATA, userdata as _);
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
WM_COPYDATA => {
|
WM_COPYDATA => {
|
||||||
let cds_ptr = lparam as *const COPYDATASTRUCT;
|
let cds_ptr = lparam as *const COPYDATASTRUCT;
|
||||||
if (*cds_ptr).dwData == WMCOPYDATA_SINGLE_INSTANCE_DATA {
|
if (*cds_ptr).dwData == WMCOPYDATA_SINGLE_INSTANCE_DATA {
|
||||||
|
let userdata = UserData::<R>::from_hwnd(hwnd);
|
||||||
|
|
||||||
let data = CStr::from_ptr((*cds_ptr).lpData as _).to_string_lossy();
|
let data = CStr::from_ptr((*cds_ptr).lpData as _).to_string_lossy();
|
||||||
let mut s = data.split('|');
|
let mut s = data.split('|');
|
||||||
let cwd = s.next().unwrap();
|
let cwd = s.next().unwrap();
|
||||||
let args = s.map(|s| s.to_string()).collect();
|
let args = s.map(|s| s.to_string()).collect();
|
||||||
callback(app_handle, args, cwd.to_string());
|
|
||||||
|
userdata.run_callback(args, cwd.to_string());
|
||||||
}
|
}
|
||||||
1
|
1
|
||||||
}
|
}
|
||||||
|
|
||||||
WM_DESTROY => {
|
WM_DESTROY => {
|
||||||
let _ = Box::from_raw(data_ptr);
|
let userdata = UserData::<R>::from_hwnd_raw(hwnd);
|
||||||
|
drop(Box::from_raw(userdata));
|
||||||
0
|
0
|
||||||
}
|
}
|
||||||
_ => DefWindowProcW(hwnd, msg, wparam, lparam),
|
_ => DefWindowProcW(hwnd, msg, wparam, lparam),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_event_target_window<R: Runtime>(class_name: &[u16], window_name: &[u16]) -> HWND {
|
fn create_event_target_window<R: Runtime>(
|
||||||
|
class_name: &[u16],
|
||||||
|
window_name: &[u16],
|
||||||
|
userdata: *const UserData<R>,
|
||||||
|
) -> HWND {
|
||||||
unsafe {
|
unsafe {
|
||||||
let class = WNDCLASSEXW {
|
let class = WNDCLASSEXW {
|
||||||
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
|
cbSize: std::mem::size_of::<WNDCLASSEXW>() as u32,
|
||||||
@@ -182,7 +211,7 @@ fn create_event_target_window<R: Runtime>(class_name: &[u16], window_name: &[u16
|
|||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
std::ptr::null_mut(),
|
std::ptr::null_mut(),
|
||||||
GetModuleHandleW(std::ptr::null()),
|
GetModuleHandleW(std::ptr::null()),
|
||||||
std::ptr::null(),
|
userdata as _,
|
||||||
);
|
);
|
||||||
SetWindowLongPtrW(
|
SetWindowLongPtrW(
|
||||||
hwnd,
|
hwnd,
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_STORE__=function(t){"use strict";var e,a;function r(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}async function s(t,e={},a){return window.__TAURI_INTERNALS__.invoke(t,e,a)}"function"==typeof SuppressedError&&SuppressedError;class i{get rid(){return function(t,e,a,r){if("a"===a&&!r)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof e?t!==e||!r:!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===a?r:"a"===a?r.call(t):r?r.value:e.get(t)}(this,e,"f")}constructor(t){e.set(this,void 0),function(t,e,a){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");e.set(t,a)}(this,e,t)}async close(){return s("plugin:resources|close",{rid:this.rid})}}async function n(t,e,a){const i={kind:"Any"};return s("plugin:event|listen",{event:t,target:i,handler:r(e)}).then((e=>async()=>async function(t,e){await s("plugin:event|unlisten",{event:t,eventId:e})}(t,e)))}async function o(t,e){return await u.load(t,e)}e=new WeakMap,function(t){t.WINDOW_RESIZED="tauri://resize",t.WINDOW_MOVED="tauri://move",t.WINDOW_CLOSE_REQUESTED="tauri://close-requested",t.WINDOW_DESTROYED="tauri://destroyed",t.WINDOW_FOCUS="tauri://focus",t.WINDOW_BLUR="tauri://blur",t.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",t.WINDOW_THEME_CHANGED="tauri://theme-changed",t.WINDOW_CREATED="tauri://window-created",t.WEBVIEW_CREATED="tauri://webview-created",t.DRAG_ENTER="tauri://drag-enter",t.DRAG_OVER="tauri://drag-over",t.DRAG_DROP="tauri://drag-drop",t.DRAG_LEAVE="tauri://drag-leave"}(a||(a={}));class u extends i{constructor(t){super(t)}static async load(t,e){const a=await s("plugin:store|load",{path:t,...e});return new u(a)}static async get(t){return await s("plugin:store|get_store",{path:t}).then((t=>t?new u(t):null))}async set(t,e){await s("plugin:store|set",{rid:this.rid,key:t,value:e})}async get(t){const[e,a]=await s("plugin:store|get",{rid:this.rid,key:t});return a?e:void 0}async has(t){return await s("plugin:store|has",{rid:this.rid,key:t})}async delete(t){return await s("plugin:store|delete",{rid:this.rid,key:t})}async clear(){await s("plugin:store|clear",{rid:this.rid})}async reset(){await s("plugin:store|reset",{rid:this.rid})}async keys(){return await s("plugin:store|keys",{rid:this.rid})}async values(){return await s("plugin:store|values",{rid:this.rid})}async entries(){return await s("plugin:store|entries",{rid:this.rid})}async length(){return await s("plugin:store|length",{rid:this.rid})}async reload(){await s("plugin:store|reload",{rid:this.rid})}async save(){await s("plugin:store|save",{rid:this.rid})}async onKeyChange(t,e){return await n("store://change",(a=>{a.payload.resourceId===this.rid&&a.payload.key===t&&e(a.payload.exists?a.payload.value:void 0)}))}async onChange(t){return await n("store://change",(e=>{e.payload.resourceId===this.rid&&t(e.payload.key,e.payload.exists?e.payload.value:void 0)}))}}return t.LazyStore=class{get store(){return this._store||(this._store=o(this.path,this.options)),this._store}constructor(t,e){this.path=t,this.options=e}async init(){await this.store}async set(t,e){return(await this.store).set(t,e)}async get(t){return(await this.store).get(t)}async has(t){return(await this.store).has(t)}async delete(t){return(await this.store).delete(t)}async clear(){await(await this.store).clear()}async reset(){await(await this.store).reset()}async keys(){return(await this.store).keys()}async values(){return(await this.store).values()}async entries(){return(await this.store).entries()}async length(){return(await this.store).length()}async reload(){await(await this.store).reload()}async save(){await(await this.store).save()}async onKeyChange(t,e){return(await this.store).onKeyChange(t,e)}async onChange(t){return(await this.store).onChange(t)}async close(){this._store&&await(await this._store).close()}},t.Store=u,t.getStore=async function(t){return await u.get(t)},t.load=o,t}({});Object.defineProperty(window.__TAURI__,"store",{value:__TAURI_PLUGIN_STORE__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_STORE__=function(t){"use strict";var e,a;function r(t,e=!1){return window.__TAURI_INTERNALS__.transformCallback(t,e)}async function s(t,e={},a){return window.__TAURI_INTERNALS__.invoke(t,e,a)}"function"==typeof SuppressedError&&SuppressedError;class i{get rid(){return function(t,e,a,r){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===a?r:"a"===a?r.call(t):r?r.value:e.get(t)}(this,e,"f")}constructor(t){e.set(this,void 0),function(t,e,a){if("function"==typeof e||!e.has(t))throw new TypeError("Cannot write private member to an object whose class did not declare it");e.set(t,a)}(this,e,t)}async close(){return s("plugin:resources|close",{rid:this.rid})}}async function n(t,e,a){const i={kind:"Any"};return s("plugin:event|listen",{event:t,target:i,handler:r(e)}).then((e=>async()=>async function(t,e){await s("plugin:event|unlisten",{event:t,eventId:e})}(t,e)))}async function o(t,e){return await u.load(t,e)}e=new WeakMap,function(t){t.WINDOW_RESIZED="tauri://resize",t.WINDOW_MOVED="tauri://move",t.WINDOW_CLOSE_REQUESTED="tauri://close-requested",t.WINDOW_DESTROYED="tauri://destroyed",t.WINDOW_FOCUS="tauri://focus",t.WINDOW_BLUR="tauri://blur",t.WINDOW_SCALE_FACTOR_CHANGED="tauri://scale-change",t.WINDOW_THEME_CHANGED="tauri://theme-changed",t.WINDOW_CREATED="tauri://window-created",t.WEBVIEW_CREATED="tauri://webview-created",t.DRAG_ENTER="tauri://drag-enter",t.DRAG_OVER="tauri://drag-over",t.DRAG_DROP="tauri://drag-drop",t.DRAG_LEAVE="tauri://drag-leave"}(a||(a={}));class u extends i{constructor(t){super(t)}static async load(t,e){const a=await s("plugin:store|load",{path:t,...e});return new u(a)}static async get(t){return await s("plugin:store|get_store",{path:t}).then((t=>t?new u(t):null))}async set(t,e){await s("plugin:store|set",{rid:this.rid,key:t,value:e})}async get(t){const[e,a]=await s("plugin:store|get",{rid:this.rid,key:t});return a?e:void 0}async has(t){return await s("plugin:store|has",{rid:this.rid,key:t})}async delete(t){return await s("plugin:store|delete",{rid:this.rid,key:t})}async clear(){await s("plugin:store|clear",{rid:this.rid})}async reset(){await s("plugin:store|reset",{rid:this.rid})}async keys(){return await s("plugin:store|keys",{rid:this.rid})}async values(){return await s("plugin:store|values",{rid:this.rid})}async entries(){return await s("plugin:store|entries",{rid:this.rid})}async length(){return await s("plugin:store|length",{rid:this.rid})}async reload(){await s("plugin:store|reload",{rid:this.rid})}async save(){await s("plugin:store|save",{rid:this.rid})}async onKeyChange(t,e){return await n("store://change",(a=>{a.payload.resourceId===this.rid&&a.payload.key===t&&e(a.payload.exists?a.payload.value:void 0)}))}async onChange(t){return await n("store://change",(e=>{e.payload.resourceId===this.rid&&t(e.payload.key,e.payload.exists?e.payload.value:void 0)}))}}return t.LazyStore=class{get store(){return this._store||(this._store=o(this.path,this.options)),this._store}constructor(t,e){this.path=t,this.options=e}async init(){await this.store}async set(t,e){return(await this.store).set(t,e)}async get(t){return(await this.store).get(t)}async has(t){return(await this.store).has(t)}async delete(t){return(await this.store).delete(t)}async clear(){await(await this.store).clear()}async reset(){await(await this.store).reset()}async keys(){return(await this.store).keys()}async values(){return(await this.store).values()}async entries(){return(await this.store).entries()}async length(){return(await this.store).length()}async reload(){await(await this.store).reload()}async save(){await(await this.store).save()}async onKeyChange(t,e){return(await this.store).onKeyChange(t,e)}async onChange(t){return(await this.store).onChange(t)}async close(){this._store&&await(await this._store).close()}},t.Store=u,t.getStore=async function(t){return await u.get(t)},t.load=o,t}({});Object.defineProperty(window.__TAURI__,"store",{value:__TAURI_PLUGIN_STORE__})}
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
"tauri": "tauri"
|
"tauri": "tauri"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tauri-apps/cli": "2.2.4",
|
"@tauri-apps/cli": "2.3.1",
|
||||||
"vite": "^6.0.0",
|
"typescript": "^5.7.3",
|
||||||
"typescript": "^5.4.7"
|
"vite": "^6.2.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,23 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## \[2.6.0]
|
||||||
|
|
||||||
|
- [`faefcc9f`](https://github.com/tauri-apps/plugins-workspace/commit/faefcc9fd8c61f709d491649e255a7fcac82c09a) ([#2430](https://github.com/tauri-apps/plugins-workspace/pull/2430) by [@goenning](https://github.com/tauri-apps/plugins-workspace/../../goenning)) Add `UpdaterBuilder::configure_client` method on Rust side, to configure the `reqwest` client used to check and download the update.
|
||||||
|
- [`ac60d589`](https://github.com/tauri-apps/plugins-workspace/commit/ac60d589eca2bbc4aed040feb18da148e66ec171) ([#2513](https://github.com/tauri-apps/plugins-workspace/pull/2513) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Enhance error logging.
|
||||||
|
|
||||||
|
## \[2.5.1]
|
||||||
|
|
||||||
|
- [`6f881293`](https://github.com/tauri-apps/plugins-workspace/commit/6f881293fcd67838f6f3f8063f536292431dd1f7) ([#2439](https://github.com/tauri-apps/plugins-workspace/pull/2439) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) Fixed an issue that caused the plugin to emit a `ReleaseNotFound` error instead of a `Reqwest` error when the http request in `check()` failed.
|
||||||
|
|
||||||
|
## \[2.5.0]
|
||||||
|
|
||||||
|
- [`5369898d`](https://github.com/tauri-apps/plugins-workspace/commit/5369898db7a6098e3e2f43436100ea556d405628) ([#2067](https://github.com/tauri-apps/plugins-workspace/pull/2067) by [@jLynx](https://github.com/tauri-apps/plugins-workspace/../../jLynx)) Fix update installation on macOS when using an user without admin privileges.
|
||||||
|
- [`5369898d`](https://github.com/tauri-apps/plugins-workspace/commit/5369898db7a6098e3e2f43436100ea556d405628) ([#2067](https://github.com/tauri-apps/plugins-workspace/pull/2067) by [@jLynx](https://github.com/tauri-apps/plugins-workspace/../../jLynx)) Remove the `UpdaterBuilder::new` function, use `UpdaterExt::updater_builder` instead.
|
||||||
|
|
||||||
|
## \[2.4.0]
|
||||||
|
|
||||||
|
- [`0afc9b6b`](https://github.com/tauri-apps/plugins-workspace/commit/0afc9b6be07bee1077f05a86285d977e57810ed9) ([#2325](https://github.com/tauri-apps/plugins-workspace/pull/2325) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The `Update` struct/object will now contain a `raw_json`/`rawJson` property to be able to read parts of server's json response that are not handled by the plugin.
|
||||||
|
|
||||||
## \[2.3.1]
|
## \[2.3.1]
|
||||||
|
|
||||||
- [`57efb47c`](https://github.com/tauri-apps/plugins-workspace/commit/57efb47c116f880477f72f02a8e4239e88007d44) ([#2235](https://github.com/tauri-apps/plugins-workspace/pull/2235) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Add `Builder::header` and `Builder::headers` method to configure default headers for updater.
|
- [`57efb47c`](https://github.com/tauri-apps/plugins-workspace/commit/57efb47c116f880477f72f02a8e4239e88007d44) ([#2235](https://github.com/tauri-apps/plugins-workspace/pull/2235) by [@amrbashir](https://github.com/tauri-apps/plugins-workspace/../../amrbashir)) Add `Builder::header` and `Builder::headers` method to configure default headers for updater.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "tauri-plugin-updater"
|
name = "tauri-plugin-updater"
|
||||||
version = "2.3.1"
|
version = "2.6.0"
|
||||||
description = "In-app updates for Tauri applications."
|
description = "In-app updates for Tauri applications."
|
||||||
edition = { workspace = true }
|
edition = { workspace = true }
|
||||||
authors = { workspace = true }
|
authors = { workspace = true }
|
||||||
@@ -30,6 +30,7 @@ tauri = { workspace = true }
|
|||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true }
|
||||||
thiserror = { workspace = true }
|
thiserror = { workspace = true }
|
||||||
|
log = { workspace = true }
|
||||||
tokio = "1"
|
tokio = "1"
|
||||||
reqwest = { version = "0.12", default-features = false, features = [
|
reqwest = { version = "0.12", default-features = false, features = [
|
||||||
"json",
|
"json",
|
||||||
@@ -43,7 +44,7 @@ base64 = "0.22"
|
|||||||
semver = { version = "1", features = ["serde"] }
|
semver = { version = "1", features = ["serde"] }
|
||||||
futures-util = "0.3"
|
futures-util = "0.3"
|
||||||
tempfile = "3"
|
tempfile = "3"
|
||||||
infer = "0.16"
|
infer = "0.19"
|
||||||
percent-encoding = "2.3"
|
percent-encoding = "2.3"
|
||||||
|
|
||||||
[target."cfg(target_os = \"windows\")".dependencies]
|
[target."cfg(target_os = \"windows\")".dependencies]
|
||||||
@@ -55,13 +56,14 @@ windows-sys = { version = "0.59.0", features = [
|
|||||||
] }
|
] }
|
||||||
|
|
||||||
[target."cfg(target_os = \"linux\")".dependencies]
|
[target."cfg(target_os = \"linux\")".dependencies]
|
||||||
dirs = "5"
|
dirs = "6"
|
||||||
tar = { version = "0.4", optional = true }
|
tar = { version = "0.4", optional = true }
|
||||||
flate2 = { version = "1", optional = true }
|
flate2 = { version = "1", optional = true }
|
||||||
|
|
||||||
[target."cfg(target_os = \"macos\")".dependencies]
|
[target."cfg(target_os = \"macos\")".dependencies]
|
||||||
tar = "0.4"
|
tar = "0.4"
|
||||||
flate2 = "1"
|
flate2 = "1"
|
||||||
|
osakit = { version = "0.3", features = ["full"] }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["rustls-tls", "zip"]
|
default = ["rustls-tls", "zip"]
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(e){"use strict";function t(e,t,s,i){if("a"===s&&!i)throw new TypeError("Private accessor was defined without a getter");if("function"==typeof t?e!==t||!i:!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?i:"a"===s?i.call(e):i?i.value:t.get(e)}function s(e,t,s,i,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var i,n,r,a;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class d{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,i.set(this,(()=>{})),n.set(this,0),r.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:a})=>{if(a==t(this,n,"f"))for(t(this,i,"f").call(this,e),s(this,n,t(this,n,"f")+1);t(this,n,"f")in t(this,r,"f");){const e=t(this,r,"f")[t(this,n,"f")];t(this,i,"f").call(this,e),delete t(this,r,"f")[t(this,n,"f")],s(this,n,t(this,n,"f")+1)}else t(this,r,"f")[a]=e}))}set onmessage(e){s(this,i,e)}get onmessage(){return t(this,i,"f")}[(i=new WeakMap,n=new WeakMap,r=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function l(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class c{get rid(){return t(this,a,"f")}constructor(e){a.set(this,void 0),s(this,a,e)}async close(){return l("plugin:resources|close",{rid:this.rid})}}a=new WeakMap;class h extends c{constructor(e){super(e.rid),this.available=e.available,this.currentVersion=e.currentVersion,this.version=e.version,this.date=e.date,this.body=e.body}async download(e,t){const s=new d;e&&(s.onmessage=e);const i=await l("plugin:updater|download",{onEvent:s,rid:this.rid,...t});this.downloadedBytes=new c(i)}async install(){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await l("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid}),this.downloadedBytes=void 0}async downloadAndInstall(e,t){const s=new d;e&&(s.onmessage=e),await l("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...t})}async close(){await(this.downloadedBytes?.close()),await super.close()}}return e.Update=h,e.check=async function(e){return e?.headers&&(e.headers=Array.from(new Headers(e.headers).entries())),await l("plugin:updater|check",{...e}).then((e=>e.available?new h(e):null))},e}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}
|
if("__TAURI__"in window){var __TAURI_PLUGIN_UPDATER__=function(e){"use strict";function t(e,t,s,n){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot read private member from an object whose class did not declare it");return"m"===s?n:"a"===s?n.call(e):n?n.value:t.get(e)}function s(e,t,s,n,i){if("function"==typeof t||!t.has(e))throw new TypeError("Cannot write private member to an object whose class did not declare it");return t.set(e,s),s}var n,i,a,r;"function"==typeof SuppressedError&&SuppressedError;const o="__TAURI_TO_IPC_KEY__";class d{constructor(){this.__TAURI_CHANNEL_MARKER__=!0,n.set(this,(()=>{})),i.set(this,0),a.set(this,[]),this.id=function(e,t=!1){return window.__TAURI_INTERNALS__.transformCallback(e,t)}((({message:e,id:r})=>{if(r==t(this,i,"f"))for(t(this,n,"f").call(this,e),s(this,i,t(this,i,"f")+1);t(this,i,"f")in t(this,a,"f");){const e=t(this,a,"f")[t(this,i,"f")];t(this,n,"f").call(this,e),delete t(this,a,"f")[t(this,i,"f")],s(this,i,t(this,i,"f")+1)}else t(this,a,"f")[r]=e}))}set onmessage(e){s(this,n,e)}get onmessage(){return t(this,n,"f")}[(n=new WeakMap,i=new WeakMap,a=new WeakMap,o)](){return`__CHANNEL__:${this.id}`}toJSON(){return this[o]()}}async function l(e,t={},s){return window.__TAURI_INTERNALS__.invoke(e,t,s)}class h{get rid(){return t(this,r,"f")}constructor(e){r.set(this,void 0),s(this,r,e)}async close(){return l("plugin:resources|close",{rid:this.rid})}}r=new WeakMap;class c extends h{constructor(e){super(e.rid),this.available=e.available,this.currentVersion=e.currentVersion,this.version=e.version,this.date=e.date,this.body=e.body,this.rawJson=e.rawJson}async download(e,t){const s=new d;e&&(s.onmessage=e);const n=await l("plugin:updater|download",{onEvent:s,rid:this.rid,...t});this.downloadedBytes=new h(n)}async install(){if(!this.downloadedBytes)throw new Error("Update.install called before Update.download");await l("plugin:updater|install",{updateRid:this.rid,bytesRid:this.downloadedBytes.rid}),this.downloadedBytes=void 0}async downloadAndInstall(e,t){const s=new d;e&&(s.onmessage=e),await l("plugin:updater|download_and_install",{onEvent:s,rid:this.rid,...t})}async close(){await(this.downloadedBytes?.close()),await super.close()}}return e.Update=c,e.check=async function(e){return e?.headers&&(e.headers=Array.from(new Headers(e.headers).entries())),await l("plugin:updater|check",{...e}).then((e=>e.available?new c(e):null))},e}({});Object.defineProperty(window.__TAURI__,"updater",{value:__TAURI_PLUGIN_UPDATER__})}
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ interface UpdateMetadata {
|
|||||||
version: string
|
version: string
|
||||||
date?: string
|
date?: string
|
||||||
body?: string
|
body?: string
|
||||||
|
rawJson: Record<string, unknown>
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Updater download event */
|
/** Updater download event */
|
||||||
@@ -57,6 +58,7 @@ class Update extends Resource {
|
|||||||
version: string
|
version: string
|
||||||
date?: string
|
date?: string
|
||||||
body?: string
|
body?: string
|
||||||
|
rawJson: Record<string, unknown>
|
||||||
private downloadedBytes?: Resource
|
private downloadedBytes?: Resource
|
||||||
|
|
||||||
constructor(metadata: UpdateMetadata) {
|
constructor(metadata: UpdateMetadata) {
|
||||||
@@ -66,6 +68,7 @@ class Update extends Resource {
|
|||||||
this.version = metadata.version
|
this.version = metadata.version
|
||||||
this.date = metadata.date
|
this.date = metadata.date
|
||||||
this.body = metadata.body
|
this.body = metadata.body
|
||||||
|
this.rawJson = metadata.rawJson
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Download the updater package */
|
/** Download the updater package */
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@tauri-apps/plugin-updater",
|
"name": "@tauri-apps/plugin-updater",
|
||||||
"version": "2.3.1",
|
"version": "2.6.0",
|
||||||
"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"
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ pub(crate) struct Metadata {
|
|||||||
version: String,
|
version: String,
|
||||||
date: Option<String>,
|
date: Option<String>,
|
||||||
body: Option<String>,
|
body: Option<String>,
|
||||||
|
raw_json: serde_json::Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct DownloadedBytes(pub Vec<u8>);
|
struct DownloadedBytes(pub Vec<u8>);
|
||||||
@@ -73,6 +74,7 @@ pub(crate) async fn check<R: Runtime>(
|
|||||||
metadata.version.clone_from(&update.version);
|
metadata.version.clone_from(&update.version);
|
||||||
metadata.date = update.date.map(|d| d.to_string());
|
metadata.date = update.date.map(|d| d.to_string());
|
||||||
metadata.body.clone_from(&update.body);
|
metadata.body.clone_from(&update.body);
|
||||||
|
metadata.raw_json.clone_from(&update.raw_json);
|
||||||
metadata.rid = Some(webview.resources_table().add(update));
|
metadata.rid = Some(webview.resources_table().add(update));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ pub trait UpdaterExt<R: Runtime> {
|
|||||||
impl<R: Runtime, T: Manager<R>> UpdaterExt<R> for T {
|
impl<R: Runtime, T: Manager<R>> UpdaterExt<R> for T {
|
||||||
fn updater_builder(&self) -> UpdaterBuilder {
|
fn updater_builder(&self) -> UpdaterBuilder {
|
||||||
let app = self.app_handle();
|
let app = self.app_handle();
|
||||||
let package_info = app.package_info();
|
|
||||||
let UpdaterState {
|
let UpdaterState {
|
||||||
config,
|
config,
|
||||||
target,
|
target,
|
||||||
@@ -78,12 +77,7 @@ impl<R: Runtime, T: Manager<R>> UpdaterExt<R> for T {
|
|||||||
headers,
|
headers,
|
||||||
} = self.state::<UpdaterState>().inner();
|
} = self.state::<UpdaterState>().inner();
|
||||||
|
|
||||||
let mut builder = UpdaterBuilder::new(
|
let mut builder = UpdaterBuilder::new(app, config.clone()).headers(headers.clone());
|
||||||
package_info.name.clone(),
|
|
||||||
package_info.version.clone(),
|
|
||||||
config.clone(),
|
|
||||||
)
|
|
||||||
.headers(headers.clone());
|
|
||||||
|
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
builder = builder.target(target);
|
builder = builder.target(target);
|
||||||
|
|||||||
+165
-45
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::{OsStr, OsString},
|
ffi::OsString,
|
||||||
io::Cursor,
|
io::Cursor,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
@@ -12,6 +12,9 @@ use std::{
|
|||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(not(target_os = "macos"))]
|
||||||
|
use std::ffi::OsStr;
|
||||||
|
|
||||||
use base64::Engine;
|
use base64::Engine;
|
||||||
use futures_util::StreamExt;
|
use futures_util::StreamExt;
|
||||||
use http::HeaderName;
|
use http::HeaderName;
|
||||||
@@ -23,7 +26,7 @@ use reqwest::{
|
|||||||
};
|
};
|
||||||
use semver::Version;
|
use semver::Version;
|
||||||
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
|
use serde::{de::Error as DeError, Deserialize, Deserializer, Serialize};
|
||||||
use tauri::{utils::platform::current_exe, Resource};
|
use tauri::{utils::platform::current_exe, AppHandle, Resource, Runtime};
|
||||||
use time::OffsetDateTime;
|
use time::OffsetDateTime;
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
@@ -93,9 +96,15 @@ impl RemoteRelease {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub type OnBeforeExit = Arc<dyn Fn() + Send + Sync + 'static>;
|
pub type OnBeforeExit = Arc<dyn Fn() + Send + Sync + 'static>;
|
||||||
|
pub type OnBeforeRequest = Arc<dyn Fn(ClientBuilder) -> ClientBuilder + Send + Sync + 'static>;
|
||||||
pub type VersionComparator = Arc<dyn Fn(Version, RemoteRelease) -> bool + Send + Sync>;
|
pub type VersionComparator = Arc<dyn Fn(Version, RemoteRelease) -> bool + Send + Sync>;
|
||||||
|
type MainThreadClosure = Box<dyn FnOnce() + Send + Sync + 'static>;
|
||||||
|
type RunOnMainThread =
|
||||||
|
Box<dyn Fn(MainThreadClosure) -> std::result::Result<(), tauri::Error> + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub struct UpdaterBuilder {
|
pub struct UpdaterBuilder {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
run_on_main_thread: RunOnMainThread,
|
||||||
app_name: String,
|
app_name: String,
|
||||||
current_version: Version,
|
current_version: Version,
|
||||||
config: Config,
|
config: Config,
|
||||||
@@ -109,21 +118,24 @@ pub struct UpdaterBuilder {
|
|||||||
installer_args: Vec<OsString>,
|
installer_args: Vec<OsString>,
|
||||||
current_exe_args: Vec<OsString>,
|
current_exe_args: Vec<OsString>,
|
||||||
on_before_exit: Option<OnBeforeExit>,
|
on_before_exit: Option<OnBeforeExit>,
|
||||||
|
configure_client: Option<OnBeforeRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UpdaterBuilder {
|
impl UpdaterBuilder {
|
||||||
/// It's prefered to use [`crate::UpdaterExt::updater_builder`] instead of
|
pub(crate) fn new<R: Runtime>(app: &AppHandle<R>, config: crate::Config) -> Self {
|
||||||
/// constructing a [`UpdaterBuilder`] with this function yourself
|
let app_ = app.clone();
|
||||||
pub fn new(app_name: String, current_version: Version, config: crate::Config) -> Self {
|
let run_on_main_thread =
|
||||||
|
move |f: Box<dyn FnOnce() + Send + Sync + 'static>| app_.run_on_main_thread(f);
|
||||||
Self {
|
Self {
|
||||||
|
run_on_main_thread: Box::new(run_on_main_thread),
|
||||||
installer_args: config
|
installer_args: config
|
||||||
.windows
|
.windows
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|w| w.installer_args.clone())
|
.map(|w| w.installer_args.clone())
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
current_exe_args: Vec::new(),
|
current_exe_args: Vec::new(),
|
||||||
app_name,
|
app_name: app.package_info().name.clone(),
|
||||||
current_version,
|
current_version: app.package_info().version.clone(),
|
||||||
config,
|
config,
|
||||||
version_comparator: None,
|
version_comparator: None,
|
||||||
executable_path: None,
|
executable_path: None,
|
||||||
@@ -133,6 +145,7 @@ impl UpdaterBuilder {
|
|||||||
timeout: None,
|
timeout: None,
|
||||||
proxy: None,
|
proxy: None,
|
||||||
on_before_exit: None,
|
on_before_exit: None,
|
||||||
|
configure_client: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -232,6 +245,19 @@ impl UpdaterBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Allows you to modify the `reqwest` client builder before the HTTP request is sent.
|
||||||
|
///
|
||||||
|
/// Note that `reqwest` crate may be updated in minor releases of tauri-plugin-updater.
|
||||||
|
/// Therefore it's recommended to pin the plugin to at least a minor version when you're using `configure_client`.
|
||||||
|
///
|
||||||
|
pub fn configure_client<F: Fn(ClientBuilder) -> ClientBuilder + Send + Sync + 'static>(
|
||||||
|
mut self,
|
||||||
|
f: F,
|
||||||
|
) -> Self {
|
||||||
|
self.configure_client.replace(Arc::new(f));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(self) -> Result<Updater> {
|
pub fn build(self) -> Result<Updater> {
|
||||||
let endpoints = self
|
let endpoints = self
|
||||||
.endpoints
|
.endpoints
|
||||||
@@ -259,6 +285,7 @@ impl UpdaterBuilder {
|
|||||||
};
|
};
|
||||||
|
|
||||||
Ok(Updater {
|
Ok(Updater {
|
||||||
|
run_on_main_thread: Arc::new(self.run_on_main_thread),
|
||||||
config: self.config,
|
config: self.config,
|
||||||
app_name: self.app_name,
|
app_name: self.app_name,
|
||||||
current_version: self.current_version,
|
current_version: self.current_version,
|
||||||
@@ -274,6 +301,7 @@ impl UpdaterBuilder {
|
|||||||
headers: self.headers,
|
headers: self.headers,
|
||||||
extract_path,
|
extract_path,
|
||||||
on_before_exit: self.on_before_exit,
|
on_before_exit: self.on_before_exit,
|
||||||
|
configure_client: self.configure_client,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -291,6 +319,8 @@ impl UpdaterBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Updater {
|
pub struct Updater {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
run_on_main_thread: Arc<RunOnMainThread>,
|
||||||
config: Config,
|
config: Config,
|
||||||
app_name: String,
|
app_name: String,
|
||||||
current_version: Version,
|
current_version: Version,
|
||||||
@@ -306,6 +336,7 @@ pub struct Updater {
|
|||||||
headers: HeaderMap,
|
headers: HeaderMap,
|
||||||
extract_path: PathBuf,
|
extract_path: PathBuf,
|
||||||
on_before_exit: Option<OnBeforeExit>,
|
on_before_exit: Option<OnBeforeExit>,
|
||||||
|
configure_client: Option<OnBeforeRequest>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
installer_args: Vec<OsString>,
|
installer_args: Vec<OsString>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
@@ -330,6 +361,7 @@ impl Updater {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mut remote_release: Option<RemoteRelease> = None;
|
let mut remote_release: Option<RemoteRelease> = None;
|
||||||
|
let mut raw_json: Option<serde_json::Value> = None;
|
||||||
let mut last_error: Option<Error> = None;
|
let mut last_error: Option<Error> = None;
|
||||||
for url in &self.endpoints {
|
for url in &self.endpoints {
|
||||||
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
|
// replace {{current_version}}, {{target}} and {{arch}} in the provided URL
|
||||||
@@ -357,14 +389,22 @@ impl Updater {
|
|||||||
.replace("{{arch}}", self.arch)
|
.replace("{{arch}}", self.arch)
|
||||||
.parse()?;
|
.parse()?;
|
||||||
|
|
||||||
|
log::debug!("checking for updates {url}");
|
||||||
|
|
||||||
let mut request = ClientBuilder::new().user_agent(UPDATER_USER_AGENT);
|
let mut request = ClientBuilder::new().user_agent(UPDATER_USER_AGENT);
|
||||||
if let Some(timeout) = self.timeout {
|
if let Some(timeout) = self.timeout {
|
||||||
request = request.timeout(timeout);
|
request = request.timeout(timeout);
|
||||||
}
|
}
|
||||||
if let Some(ref proxy) = self.proxy {
|
if let Some(ref proxy) = self.proxy {
|
||||||
|
log::debug!("using proxy {proxy}");
|
||||||
let proxy = reqwest::Proxy::all(proxy.as_str())?;
|
let proxy = reqwest::Proxy::all(proxy.as_str())?;
|
||||||
request = request.proxy(proxy);
|
request = request.proxy(proxy);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(ref configure_client) = self.configure_client {
|
||||||
|
request = configure_client(request);
|
||||||
|
}
|
||||||
|
|
||||||
let response = request
|
let response = request
|
||||||
.build()?
|
.build()?
|
||||||
.get(url)
|
.get(url)
|
||||||
@@ -372,25 +412,43 @@ impl Updater {
|
|||||||
.send()
|
.send()
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
if let Ok(res) = response {
|
match response {
|
||||||
if res.status().is_success() {
|
Ok(res) => {
|
||||||
// no updates found!
|
if res.status().is_success() {
|
||||||
if StatusCode::NO_CONTENT == res.status() {
|
// no updates found!
|
||||||
return Ok(None);
|
if StatusCode::NO_CONTENT == res.status() {
|
||||||
};
|
log::debug!("update endpoint returned 204 No Content");
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
match serde_json::from_value::<RemoteRelease>(res.json().await?)
|
let update_response: serde_json::Value = res.json().await?;
|
||||||
.map_err(Into::into)
|
log::debug!("update response: {update_response:?}");
|
||||||
{
|
raw_json = Some(update_response.clone());
|
||||||
Ok(release) => {
|
match serde_json::from_value::<RemoteRelease>(update_response)
|
||||||
last_error = None;
|
.map_err(Into::into)
|
||||||
remote_release = Some(release);
|
{
|
||||||
// we found a relase, break the loop
|
Ok(release) => {
|
||||||
break;
|
log::debug!("parsed release response {release:?}");
|
||||||
|
last_error = None;
|
||||||
|
remote_release = Some(release);
|
||||||
|
// we found a release, break the loop
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("failed to deserialize update response: {err}");
|
||||||
|
last_error = Some(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(err) => last_error = Some(err),
|
} else {
|
||||||
|
log::error!(
|
||||||
|
"update endpoint did not respond with a successful status code"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("failed to check for updates: {err}");
|
||||||
|
last_error = Some(err.into())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,6 +468,7 @@ impl Updater {
|
|||||||
|
|
||||||
let update = if should_update {
|
let update = if should_update {
|
||||||
Some(Update {
|
Some(Update {
|
||||||
|
run_on_main_thread: self.run_on_main_thread.clone(),
|
||||||
config: self.config.clone(),
|
config: self.config.clone(),
|
||||||
on_before_exit: self.on_before_exit.clone(),
|
on_before_exit: self.on_before_exit.clone(),
|
||||||
app_name: self.app_name.clone(),
|
app_name: self.app_name.clone(),
|
||||||
@@ -421,11 +480,13 @@ impl Updater {
|
|||||||
download_url: release.download_url(&self.json_target)?.to_owned(),
|
download_url: release.download_url(&self.json_target)?.to_owned(),
|
||||||
body: release.notes.clone(),
|
body: release.notes.clone(),
|
||||||
signature: release.signature(&self.json_target)?.to_owned(),
|
signature: release.signature(&self.json_target)?.to_owned(),
|
||||||
|
raw_json: raw_json.unwrap(),
|
||||||
timeout: self.timeout,
|
timeout: self.timeout,
|
||||||
proxy: self.proxy.clone(),
|
proxy: self.proxy.clone(),
|
||||||
headers: self.headers.clone(),
|
headers: self.headers.clone(),
|
||||||
installer_args: self.installer_args.clone(),
|
installer_args: self.installer_args.clone(),
|
||||||
current_exe_args: self.current_exe_args.clone(),
|
current_exe_args: self.current_exe_args.clone(),
|
||||||
|
configure_client: self.configure_client.clone(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@@ -437,6 +498,8 @@ impl Updater {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Update {
|
pub struct Update {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
run_on_main_thread: Arc<RunOnMainThread>,
|
||||||
config: Config,
|
config: Config,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
on_before_exit: Option<OnBeforeExit>,
|
on_before_exit: Option<OnBeforeExit>,
|
||||||
@@ -454,6 +517,8 @@ pub struct Update {
|
|||||||
pub download_url: Url,
|
pub download_url: Url,
|
||||||
/// Signature announced
|
/// Signature announced
|
||||||
pub signature: String,
|
pub signature: String,
|
||||||
|
/// The raw version of server's JSON response. Useful if the response contains additional fields that the updater doesn't handle.
|
||||||
|
pub raw_json: serde_json::Value,
|
||||||
/// Request timeout
|
/// Request timeout
|
||||||
pub timeout: Option<Duration>,
|
pub timeout: Option<Duration>,
|
||||||
/// Request proxy
|
/// Request proxy
|
||||||
@@ -470,6 +535,7 @@ pub struct Update {
|
|||||||
installer_args: Vec<OsString>,
|
installer_args: Vec<OsString>,
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
current_exe_args: Vec<OsString>,
|
current_exe_args: Vec<OsString>,
|
||||||
|
configure_client: Option<OnBeforeRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Resource for Update {}
|
impl Resource for Update {}
|
||||||
@@ -498,6 +564,9 @@ impl Update {
|
|||||||
let proxy = reqwest::Proxy::all(proxy.as_str())?;
|
let proxy = reqwest::Proxy::all(proxy.as_str())?;
|
||||||
request = request.proxy(proxy);
|
request = request.proxy(proxy);
|
||||||
}
|
}
|
||||||
|
if let Some(ref configure_client) = self.configure_client {
|
||||||
|
request = configure_client(request);
|
||||||
|
}
|
||||||
let response = request
|
let response = request
|
||||||
.build()?
|
.build()?
|
||||||
.get(self.download_url.clone())
|
.get(self.download_url.clone())
|
||||||
@@ -646,6 +715,7 @@ impl Update {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(on_before_exit) = self.on_before_exit.as_ref() {
|
if let Some(on_before_exit) = self.on_before_exit.as_ref() {
|
||||||
|
log::debug!("running on_before_exit hook");
|
||||||
on_before_exit();
|
on_before_exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -814,6 +884,7 @@ impl Update {
|
|||||||
|
|
||||||
#[cfg(feature = "zip")]
|
#[cfg(feature = "zip")]
|
||||||
if infer::archive::is_gz(bytes) {
|
if infer::archive::is_gz(bytes) {
|
||||||
|
log::debug!("extracting AppImage");
|
||||||
// extract the buffer to the tmp_dir
|
// extract the buffer to the tmp_dir
|
||||||
// we extract our signed archive into our final directory without any temp file
|
// we extract our signed archive into our final directory without any temp file
|
||||||
let archive = Cursor::new(bytes);
|
let archive = Cursor::new(bytes);
|
||||||
@@ -837,6 +908,7 @@ impl Update {
|
|||||||
return Err(Error::BinaryNotFoundInArchive);
|
return Err(Error::BinaryNotFoundInArchive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log::debug!("rewriting AppImage");
|
||||||
return match std::fs::write(&self.extract_path, bytes)
|
return match std::fs::write(&self.extract_path, bytes)
|
||||||
.and_then(|_| std::fs::set_permissions(&self.extract_path, permissions))
|
.and_then(|_| std::fs::set_permissions(&self.extract_path, permissions))
|
||||||
{
|
{
|
||||||
@@ -890,6 +962,7 @@ impl Update {
|
|||||||
fn install_deb(&self, bytes: &[u8]) -> Result<()> {
|
fn install_deb(&self, bytes: &[u8]) -> Result<()> {
|
||||||
// First verify the bytes are actually a .deb package
|
// First verify the bytes are actually a .deb package
|
||||||
if !infer::archive::is_deb(bytes) {
|
if !infer::archive::is_deb(bytes) {
|
||||||
|
log::warn!("update is not a valid deb package");
|
||||||
return Err(Error::InvalidUpdaterFormat);
|
return Err(Error::InvalidUpdaterFormat);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -932,6 +1005,7 @@ impl Update {
|
|||||||
.status()
|
.status()
|
||||||
{
|
{
|
||||||
if status.success() {
|
if status.success() {
|
||||||
|
log::debug!("installed deb with pkexec");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -939,6 +1013,7 @@ impl Update {
|
|||||||
// 2. Try zenity or kdialog for a graphical sudo experience
|
// 2. Try zenity or kdialog for a graphical sudo experience
|
||||||
if let Ok(password) = self.get_password_graphically() {
|
if let Ok(password) = self.get_password_graphically() {
|
||||||
if self.install_with_sudo(deb_path, &password)? {
|
if self.install_with_sudo(deb_path, &password)? {
|
||||||
|
log::debug!("installed deb with GUI sudo");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -951,6 +1026,7 @@ impl Update {
|
|||||||
.status()?;
|
.status()?;
|
||||||
|
|
||||||
if status.success() {
|
if status.success() {
|
||||||
|
log::debug!("installed deb with sudo");
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::DebInstallFailed)
|
Err(Error::DebInstallFailed)
|
||||||
@@ -1026,42 +1102,86 @@ impl Update {
|
|||||||
let cursor = Cursor::new(bytes);
|
let cursor = Cursor::new(bytes);
|
||||||
let mut extracted_files: Vec<PathBuf> = Vec::new();
|
let mut extracted_files: Vec<PathBuf> = Vec::new();
|
||||||
|
|
||||||
// the first file in the tar.gz will always be
|
// Create temp directories for backup and extraction
|
||||||
// <app_name>/Contents
|
let tmp_backup_dir = tempfile::Builder::new()
|
||||||
let tmp_dir = tempfile::Builder::new()
|
|
||||||
.prefix("tauri_current_app")
|
.prefix("tauri_current_app")
|
||||||
.tempdir()?;
|
.tempdir()?;
|
||||||
|
|
||||||
// create backup of our current app
|
let tmp_extract_dir = tempfile::Builder::new()
|
||||||
std::fs::rename(&self.extract_path, tmp_dir.path())?;
|
.prefix("tauri_updated_app")
|
||||||
|
.tempdir()?;
|
||||||
|
|
||||||
let decoder = GzDecoder::new(cursor);
|
let decoder = GzDecoder::new(cursor);
|
||||||
let mut archive = tar::Archive::new(decoder);
|
let mut archive = tar::Archive::new(decoder);
|
||||||
|
|
||||||
std::fs::create_dir(&self.extract_path)?;
|
// Extract files to temporary directory
|
||||||
|
|
||||||
for entry in archive.entries()? {
|
for entry in archive.entries()? {
|
||||||
let mut entry = entry?;
|
let mut entry = entry?;
|
||||||
|
|
||||||
// skip the first folder (should be the app name)
|
|
||||||
let collected_path: PathBuf = entry.path()?.iter().skip(1).collect();
|
let collected_path: PathBuf = entry.path()?.iter().skip(1).collect();
|
||||||
let extraction_path = &self.extract_path.join(collected_path);
|
let extraction_path = tmp_extract_dir.path().join(&collected_path);
|
||||||
|
|
||||||
// if something went wrong during the extraction, we should restore previous app
|
// Ensure parent directories exist
|
||||||
if let Err(err) = entry.unpack(extraction_path) {
|
if let Some(parent) = extraction_path.parent() {
|
||||||
for file in extracted_files.iter().rev() {
|
std::fs::create_dir_all(parent)?;
|
||||||
// delete all the files we extracted
|
|
||||||
if file.is_dir() {
|
|
||||||
std::fs::remove_dir(file)?;
|
|
||||||
} else {
|
|
||||||
std::fs::remove_file(file)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
std::fs::rename(tmp_dir.path(), &self.extract_path)?;
|
|
||||||
return Err(err.into());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extracted_files.push(extraction_path.to_path_buf());
|
if let Err(err) = entry.unpack(&extraction_path) {
|
||||||
|
// Cleanup on error
|
||||||
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
extracted_files.push(extraction_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to move the current app to backup
|
||||||
|
let move_result = std::fs::rename(
|
||||||
|
&self.extract_path,
|
||||||
|
tmp_backup_dir.path().join("current_app"),
|
||||||
|
);
|
||||||
|
let need_authorization = if let Err(err) = move_result {
|
||||||
|
if err.kind() == std::io::ErrorKind::PermissionDenied {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
||||||
|
return Err(err.into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
|
|
||||||
|
if need_authorization {
|
||||||
|
log::debug!("app installation needs admin privileges");
|
||||||
|
// Use AppleScript to perform moves with admin privileges
|
||||||
|
let apple_script = format!(
|
||||||
|
"do shell script \"rm -rf '{src}' && mv -f '{new}' '{src}'\" with administrator privileges",
|
||||||
|
src = self.extract_path.display(),
|
||||||
|
new = tmp_extract_dir.path().display()
|
||||||
|
);
|
||||||
|
|
||||||
|
let (tx, rx) = std::sync::mpsc::channel();
|
||||||
|
let res = (self.run_on_main_thread)(Box::new(move || {
|
||||||
|
let mut script =
|
||||||
|
osakit::Script::new_from_source(osakit::Language::AppleScript, &apple_script);
|
||||||
|
script.compile().expect("invalid AppleScript");
|
||||||
|
let r = script.execute();
|
||||||
|
tx.send(r).unwrap();
|
||||||
|
}));
|
||||||
|
let result = rx.recv().unwrap();
|
||||||
|
|
||||||
|
if res.is_err() || result.is_err() {
|
||||||
|
std::fs::remove_dir_all(tmp_extract_dir.path()).ok();
|
||||||
|
return Err(Error::Io(std::io::Error::new(
|
||||||
|
std::io::ErrorKind::PermissionDenied,
|
||||||
|
"Failed to move the new app into place",
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove existing directory if it exists
|
||||||
|
if self.extract_path.exists() {
|
||||||
|
std::fs::remove_dir_all(&self.extract_path)?;
|
||||||
|
}
|
||||||
|
// Move the new app to the target path
|
||||||
|
std::fs::rename(tmp_extract_dir.path(), &self.extract_path)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _ = std::process::Command::new("touch")
|
let _ = std::process::Command::new("touch")
|
||||||
|
|||||||
@@ -63,8 +63,6 @@ fn build_app(cwd: &Path, config: &Config, bundle_updater: bool, target: BundleTa
|
|||||||
if bundle_updater {
|
if bundle_updater {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", "msi", "nsis"]);
|
command.args(["--bundles", "msi", "nsis"]);
|
||||||
|
|
||||||
command.args(["--bundles", "updater"]);
|
|
||||||
} else {
|
} else {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", target.name()]);
|
command.args(["--bundles", target.name()]);
|
||||||
|
|||||||
@@ -67,8 +67,6 @@ mod v1 {
|
|||||||
if bundle_updater {
|
if bundle_updater {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", "msi", "nsis"]);
|
command.args(["--bundles", "msi", "nsis"]);
|
||||||
|
|
||||||
command.args(["--bundles", "updater"]);
|
|
||||||
} else {
|
} else {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", target.name()]);
|
command.args(["--bundles", target.name()]);
|
||||||
@@ -173,8 +171,6 @@ mod v2 {
|
|||||||
if bundle_updater {
|
if bundle_updater {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", "msi", "nsis"]);
|
command.args(["--bundles", "msi", "nsis"]);
|
||||||
|
|
||||||
command.args(["--bundles", "updater"]);
|
|
||||||
} else {
|
} else {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
command.args(["--bundles", target.name()]);
|
command.args(["--bundles", target.name()]);
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user