Merge remote-tracking branch 'origin/v2' into feat/scanner

pull/536/head
Lucas Nogueira 2 years ago
commit b9462bd2ce
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7

@ -0,0 +1,11 @@
[advisories]
ignore = [
# time 0.1
"RUSTSEC-2020-0071",
# needs sqlx 0.7 (still in alpha)
"RUSTSEC-2022-0090",
# wry needs kuchiki on Android
"RUSTSEC-2023-0019",
# atty is only used when the `colored` feature is enabled on tauri-plugin-log
"RUSTSEC-2021-0145"
]

@ -3,12 +3,12 @@
"pkgManagers": { "pkgManagers": {
"javascript": { "javascript": {
"version": true, "version": true,
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js npm ${ pkgFile.pkg.name } ${ pkgFile.pkg.version }", "getPublishedVersion": "node ../../.scripts/covector/package-latest-version.cjs npm ${ pkgFile.pkg.name } ${ pkgFile.pkg.version }",
"publish": ["pnpm build", "pnpm publish --access public --no-git-checks"] "publish": ["pnpm build", "pnpm publish --access public --no-git-checks"]
}, },
"rust": { "rust": {
"version": true, "version": true,
"getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js cargo ${ pkgFile.pkg.package.name } ${ pkgFile.pkg.package.version }", "getPublishedVersion": "node ../../.scripts/covector/package-latest-version.cjs cargo ${ pkgFile.pkg.package.name } ${ pkgFile.pkg.package.version }",
"publish": [ "publish": [
{ {
"command": "cargo package --no-verify", "command": "cargo package --no-verify",
@ -33,85 +33,130 @@
} }
}, },
"packages": { "packages": {
"api-example": {
"path": "./examples/api/src-tauri",
"manager": "rust",
"publish": false,
"dependencies": [
"app",
"log-plugin",
"cli",
"clipboard",
"dialog",
"fs",
"global-shortcut",
"http",
"notification",
"os",
"process",
"shell",
"updater",
"window"
]
},
"api-example-js": {
"path": "./examples/api",
"manager": "javascript",
"publish": false,
"dependencies": [
"app-js",
"log-js",
"cli-js",
"clipboard-js",
"dialog-js",
"fs-js",
"global-shortcut-js",
"http-js",
"notification-js",
"os-js",
"process-js",
"shell-js",
"updater-js",
"window-js"
]
},
"app": {
"path": "./plugins/app",
"manager": "rust"
},
"app-js": {
"path": "./plugins/app",
"manager": "javascript"
},
"authenticator": { "authenticator": {
"path": "./plugins/authenticator", "path": "./plugins/authenticator",
"manager": "rust-disabled" "manager": "rust"
}, },
"authenticator-js": { "authenticator-js": {
"path": "./plugins/authenticator", "path": "./plugins/authenticator",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"autostart": { "autostart": {
"path": "./plugins/autostart", "path": "./plugins/autostart",
"manager": "rust-disabled" "manager": "rust"
}, },
"autostart-js": { "autostart-js": {
"path": "./plugins/autostart", "path": "./plugins/autostart",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"cli": { "cli": {
"path": "./plugins/cli", "path": "./plugins/cli",
"manager": "rust-disabled" "manager": "rust"
}, },
"cli-js": { "cli-js": {
"path": "./plugins/cli", "path": "./plugins/cli",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"clipboard": { "clipboard-manager": {
"path": "./plugins/clipboard", "path": "./plugins/clipboard-manager",
"manager": "rust-disabled" "manager": "rust"
}, },
"clipboard-js": { "clipboard-manager-js": {
"path": "./plugins/clipboard", "path": "./plugins/clipboard-manager",
"manager": "javascript-disabled" "manager": "javascript"
},
"dialog": {
"path": "./plugins/dialog",
"manager": "rust-disabled"
},
"dialog-js": {
"path": "./plugins/dialog",
"manager": "javascript-disabled"
}, },
"fs": { "fs": {
"path": "./plugins/fs", "path": "./plugins/fs",
"manager": "rust-disabled" "manager": "rust"
}, },
"fs-js": { "fs-js": {
"path": "./plugins/fs", "path": "./plugins/fs",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"fs-watch": { "dialog": {
"path": "./plugins/fs-watch", "path": "./plugins/dialog",
"manager": "rust-disabled" "manager": "rust",
"dependencies": ["fs"]
}, },
"fs-watch-js": { "dialog-js": {
"path": "./plugins/fs-watch", "path": "./plugins/dialog",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"global-shortcut": { "global-shortcut": {
"path": "./plugins/global-shortcut", "path": "./plugins/global-shortcut",
"manager": "rust-disabled" "manager": "rust"
}, },
"global-shortcut-js": { "global-shortcut-js": {
"path": "./plugins/global-shortcut", "path": "./plugins/global-shortcut",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"http": { "http": {
"path": "./plugins/http", "path": "./plugins/http",
"manager": "rust-disabled" "manager": "rust",
"dependencies": ["fs"]
}, },
"http-js": { "http-js": {
"path": "./plugins/http", "path": "./plugins/http",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"localhost": { "localhost": {
@ -119,27 +164,37 @@
"manager": "rust" "manager": "rust"
}, },
"log": { "log-plugin": {
"path": "./plugins/log", "path": "./plugins/log",
"manager": "rust-disabled" "manager": "rust"
}, },
"log-js": { "log-js": {
"path": "./plugins/log", "path": "./plugins/log",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"notification": { "notification": {
"path": "./plugins/notification", "path": "./plugins/notification",
"manager": "rust-disabled" "manager": "rust"
}, },
"notification-js": { "notification-js": {
"path": "./plugins/notification", "path": "./plugins/notification",
"manager": "javascript-disabled" "manager": "javascript"
},
"os": {
"path": "./plugins/os",
"manager": "rust"
},
"os-js": {
"path": "./plugins/os",
"manager": "javascript"
}, },
"persisted-scope": { "persisted-scope": {
"path": "./plugins/persisted-scope", "path": "./plugins/persisted-scope",
"manager": "rust" "manager": "rust",
"dependencies": ["fs"]
}, },
"positioner": { "positioner": {
@ -148,66 +203,114 @@
}, },
"positioner-js": { "positioner-js": {
"path": "./plugins/positioner", "path": "./plugins/positioner",
"manager": "javascript-disabled" "manager": "javascript"
},
"process": {
"path": "./plugins/process",
"manager": "rust"
},
"process-js": {
"path": "./plugins/process",
"manager": "javascript"
}, },
"shell": { "shell": {
"path": "./plugins/shell", "path": "./plugins/shell",
"manager": "rust-disabled" "manager": "rust"
}, },
"shell-js": { "shell-js": {
"path": "./plugins/shell", "path": "./plugins/shell",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"single-instance": { "single-instance": {
"path": "./plugins/single-instance", "path": "./plugins/single-instance",
"manager": "rust-disabled" "manager": "rust"
}, },
"sql": { "sql": {
"path": "./plugins/sql", "path": "./plugins/sql",
"manager": "rust-disabled" "manager": "rust",
"publish": [
{
"command": "cargo package --no-verify",
"dryRunCommand": true
},
{
"command": "echo '<details>\n<summary><em><h4>Cargo Publish</h4></em></summary>\n\n```'",
"dryRunCommand": true,
"pipe": true
},
{
"command": "cargo publish --features sqlite",
"dryRunCommand": "cargo publish --features sqlite --dry-run",
"pipe": true
},
{
"command": "echo '```\n\n</details>\n'",
"dryRunCommand": true,
"pipe": true
}
]
}, },
"sql-js": { "sql-js": {
"path": "./plugins/sql", "path": "./plugins/sql",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"store": { "store": {
"path": "./plugins/store", "path": "./plugins/store",
"manager": "rust-disabled" "manager": "rust"
}, },
"store-js": { "store-js": {
"path": "./plugins/store", "path": "./plugins/store",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"stronghold": { "stronghold": {
"path": "./plugins/stronghold", "path": "./plugins/stronghold",
"manager": "rust-disabled" "manager": "rust"
}, },
"stronghold-js": { "stronghold-js": {
"path": "./plugins/stronghold", "path": "./plugins/stronghold",
"manager": "javascript-disabled" "manager": "javascript"
},
"updater": {
"path": "./plugins/updater",
"manager": "rust"
},
"updater-js": {
"path": "./plugins/updater",
"manager": "javascript"
}, },
"upload": { "upload": {
"path": "./plugins/upload", "path": "./plugins/upload",
"manager": "rust-disabled" "manager": "rust"
}, },
"upload-js": { "upload-js": {
"path": "./plugins/upload", "path": "./plugins/upload",
"manager": "javascript-disabled" "manager": "javascript"
}, },
"websocket": { "websocket": {
"path": "./plugins/websocket", "path": "./plugins/websocket",
"manager": "rust-disabled" "manager": "rust"
}, },
"websocket-js": { "websocket-js": {
"path": "./plugins/websocket", "path": "./plugins/websocket",
"manager": "javascript-disabled" "manager": "javascript"
},
"window": {
"path": "./plugins/window",
"manager": "rust"
},
"window-js": {
"path": "./plugins/window",
"manager": "javascript"
}, },
"window-state": { "window-state": {
@ -216,7 +319,7 @@
}, },
"window-state-js": { "window-state-js": {
"path": "./plugins/window-state", "path": "./plugins/window-state",
"manager": "javascript-disabled" "manager": "javascript"
} }
} }
} }

@ -0,0 +1,5 @@
---
"notification": patch
---
Use `window.__TAURI_INVOKE__` instead of `window.__TAURI__` in init.js, fixes usage in apps without `withGlobalTauri` enabled.

@ -0,0 +1,5 @@
---
"notification": patch
---
Play a default sound when showing a notification on Windows.

@ -0,0 +1,11 @@
---
"os": minor
"os-js": minor
---
The os plugin is recieving a few changes to improve consistency and add new features:
- Renamed `Kind` enum to `OsType` and `kind()` function to `os_type()`.
- Added `family()`,`exe_extension()`, and `hostname()` functions and their equivalents for JS.
- Removed `tempdir()` function and its equivalent on JS, use `std::env::temp_dir` instead of `temp_dir` from `tauri::path::PathResolver::temp_dir` and `path.tempDir` on JS.
- Modified `platform()` implementation to return `windows` instead of `win32` and `macos` instead of `darwin` to align with Rust's `std::env::consts::OS`

@ -1,5 +0,0 @@
---
persisted-scope: patch
---
Recursively unescape saved patterns before allowing/forbidding them. This effectively prevents `.persisted-scope` files from blowing up, which caused Out-Of-Memory issues, while automatically fixing existing broken files seamlessly.

@ -0,0 +1,9 @@
{
"tag": "alpha",
"changes": [
".changes/notification-init-script.md",
".changes/notification-sound.md",
".changes/stronghold-constructor.md",
".changes/v2-alpha.md"
]
}

@ -0,0 +1,5 @@
---
"stronghold-js": minor
---
Added `Stronghold.load` and removed its constructor.

@ -0,0 +1,53 @@
---
"app": major
"app-js": major
"authenticator": major
"authenticator-js": major
"autostart": major
"autostart-js": major
"cli": major
"cli-js": major
"clipboard-manager": major
"clipboard-manager-js": major
"dialog": major
"dialog-js": major
"fs": major
"fs-js": major
"global-shortcut": major
"global-shortcut-js": major
"http": major
"http-js": major
"localhost": major
"log-plugin": major
"log-js": major
"notification": major
"notification-js": major
"os": major
"os-js": major
"persisted-scope": major
"positioner": major
"positioner-js": major
"process": major
"process-js": major
"shell": major
"shell-js": major
"single-instance": major
"sql": major
"sql-js": major
"store": major
"store-js": major
"stronghold": major
"stronghold-js": major
"updater": major
"updater-js": major
"upload": major
"upload-js": major
"websocket": major
"websocket-js": major
"window": major
"window-js": major
"window-state": major
"window-state-js": major
---
First v2 alpha release!

@ -0,0 +1,5 @@
---
"window-state": "patch"
---
Correctly set decoration state if no saved state xists

@ -0,0 +1,5 @@
---
"window-state-js": "patch"
---
Correctly propagate the promise inside `saveWindowState`, `restoreState` and `restoreStateCurrent` so callers can choose to `await` them.

@ -2,3 +2,4 @@ target
node_modules node_modules
dist dist
dist-js dist-js
api-iife.js

@ -1,4 +1,7 @@
#!/bin/bash #!/bin/bash
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
## Environment used by this script: ## Environment used by this script:
# #

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Audit JavaScript name: Audit JavaScript
on: on:

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Audit Rust name: Audit Rust
on: on:

@ -0,0 +1,155 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check generated files
on:
pull_request:
paths:
- ".github/workflows/check-generated-files.yml"
- "**/guest-js/**"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
app:
- .github/workflows/check-generated-files.yml
- plugins/app/guest-js/**
- plugins/app/src/api-iife.js
authenticator:
- .github/workflows/check-generated-files.yml
- plugins/authenticator/guest-js/**
- plugins/authenticator/src/api-iife.js
autostart:
- .github/workflows/check-generated-files.yml
- plugins/autostart/guest-js/**
- plugins/autostart/src/api-iife.js
cli:
- .github/workflows/check-generated-files.yml
- plugins/cli/guest-js/**
- plugins/cli/src/api-iife.js
clipboard-manager:
- .github/workflows/check-generated-files.yml
- plugins/clipboard-manager/guest-js/**
- plugins/clipboard-manager/src/api-iife.js
dialog:
- .github/workflows/check-generated-files.yml
- plugins/dialog/guest-js/**
- plugins/dialog/src/api-iife.js
fs:
- .github/workflows/check-generated-files.yml
- plugins/fs/guest-js/**
- plugins/fs/src/api-iife.js
global-shortcut:
- .github/workflows/check-generated-files.yml
- plugins/global-shortcut/guest-js/**
- plugins/global-shortcut/src/api-iife.js
http:
- .github/workflows/check-generated-files.yml
- plugins/http/guest-js/**
- plugins/http/src/api-iife.js
log:
- .github/workflows/check-generated-files.yml
- plugins/log/guest-js/**
- plugins/log/src/api-iife.js
notification:
- .github/workflows/check-generated-files.yml
- plugins/notification/guest-js/**
- plugins/notification/src/api-iife.js
os:
- .github/workflows/check-generated-files.yml
- plugins/os/guest-js/**
- plugins/os/src/api-iife.js
positioner:
- .github/workflows/check-generated-files.yml
- plugins/positioner/guest-js/**
- plugins/positioner/src/api-iife.js
process:
- .github/workflows/check-generated-files.yml
- plugins/process/guest-js/**
- plugins/process/src/api-iife.js
shell:
- .github/workflows/check-generated-files.yml
- plugins/shell/guest-js/**
- plugins/shell/src/api-iife.js
sql:
- .github/workflows/check-generated-files.yml
- plugins/sql/guest-js/**
- plugins/sql/src/api-iife.js
store:
- .github/workflows/check-generated-files.yml
- plugins/store/guest-js/**
- plugins/store/src/api-iife.js
stronghold:
- .github/workflows/check-generated-files.yml
- plugins/stronghold/guest-js/**
- plugins/stronghold/src/api-iife.js
updater:
- .github/workflows/check-generated-files.yml
- plugins/updater/guest-js/**
- plugins/updater/src/api-iife.js
upload:
- .github/workflows/check-generated-files.yml
- plugins/upload/guest-js/**
- plugins/upload/src/api-iife.js
websocket:
- .github/workflows/check-generated-files.yml
- plugins/websocket/guest-js/**
- plugins/websocket/src/api-iife.js
window:
- .github/workflows/check-generated-files.yml
- plugins/window/guest-js/**
- plugins/window/src/api-iife.js
window-state:
- .github/workflows/check-generated-files.yml
- plugins/window-state/guest-js/**
- plugins/window-state/src/api-iife.js
test:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Cache pnpm modules
uses: actions/cache@v3
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- uses: actions/setup-node@v3
with:
node-version: 18
- uses: pnpm/action-setup@v2
with:
version: 7.x.x
run_install: true
- name: build api
working-directory: plugins/${{ matrix.package }}
run: pnpm install && pnpm build
- name: check diff
run: |
./.scripts/ci/has-diff.sh

@ -0,0 +1,28 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check license header
on:
pull_request:
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: dorny/paths-filter@v2
id: filter
with:
list-files: shell
filters: |
added:
- added: '**'
- name: check header license on new files
if: ${{ steps.filter.outputs.added == 'true' }}
run: node .scripts/ci/check-license-header.js ${{ steps.filter.outputs.added_files }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: covector status name: covector status
on: [pull_request] on: [pull_request]
@ -10,7 +14,7 @@ jobs:
with: with:
fetch-depth: 0 # required for use of git history fetch-depth: 0 # required for use of git history
- name: covector status - name: covector status
uses: jbolda/covector/packages/action@covector-v0.8 uses: jbolda/covector/packages/action@covector-v0
id: covector id: covector
with: with:
command: "status" command: "status"

@ -0,0 +1,68 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: version or publish
on:
push:
branches:
- v2
jobs:
version-or-publish:
runs-on: ubuntu-latest
timeout-minutes: 65
outputs:
change: ${{ steps.covector.outputs.change }}
commandRan: ${{ steps.covector.outputs.commandRan }}
successfulPublish: ${{ steps.covector.outputs.successfulPublish }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # required for use of git history
- uses: actions/setup-node@v3
with:
node-version: "lts/*"
registry-url: "https://registry.npmjs.org"
- uses: pnpm/action-setup@v2
with:
version: 7.x.x
run_install: true
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: cargo login
run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }}
- name: git config
run: |
git config --global user.name "${{ github.event.pusher.name }}"
git config --global user.email "${{ github.event.pusher.email }}"
- name: covector version or publish (publish when no change files present)
uses: jbolda/covector/packages/action@covector-v0
id: covector
env:
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
with:
token: ${{ secrets.GITHUB_TOKEN }}
command: "version-or-publish"
createRelease: true
- name: Create Pull Request With Versions Bumped
id: cpr
uses: tauri-apps/create-pull-request@v3
if: steps.covector.outputs.commandRan == 'version'
with:
title: "Publish New Versions (v2)"
commit-message: "publish new versions"
labels: "version updates"
branch: "release-v2"
body: ${{ steps.covector.outputs.change }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: version or publish name: version or publish
on: on:
@ -29,6 +33,11 @@ jobs:
version: 7.x.x version: 7.x.x
run_install: true run_install: true
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: cargo login - name: cargo login
run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }} run: cargo login ${{ secrets.ORG_CRATES_IO_TOKEN }}
@ -38,7 +47,7 @@ jobs:
git config --global user.email "${{ github.event.pusher.email }}" git config --global user.email "${{ github.event.pusher.email }}"
- name: covector version or publish (publish when no change files present) - name: covector version or publish (publish when no change files present)
uses: jbolda/covector/packages/action@covector-v0.8 uses: jbolda/covector/packages/action@covector-v0
id: covector id: covector
env: env:
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Lint JavaScript name: Lint JavaScript
on: on:

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Lint Rust name: Lint Rust
on: on:
@ -8,6 +12,7 @@ on:
paths: paths:
- ".github/workflows/lint-rust.yml" - ".github/workflows/lint-rust.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml" - "**/Cargo.toml"
pull_request: pull_request:
branches: branches:
@ -16,6 +21,7 @@ on:
paths: paths:
- ".github/workflows/lint-rust.yml" - ".github/workflows/lint-rust.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml" - "**/Cargo.toml"
concurrency: concurrency:
@ -23,10 +29,108 @@ concurrency:
cancel-in-progress: true cancel-in-progress: true
jobs: jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
tauri-plugin-app:
- .github/workflows/lint-rust.yml
- plugins/app/**
tauri-plugin-authenticator:
- .github/workflows/lint-rust.yml
- plugins/authenticator/**
tauri-plugin-autostart:
- .github/workflows/lint-rust.yml
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/lint-rust.yml
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/lint-rust.yml
- plugins/clipboard-manager/**
tauri-plugin-dialog:
- .github/workflows/lint-rust.yml
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/lint-rust.yml
- plugins/fs/**
tauri-plugin-global-shortcut:
- .github/workflows/lint-rust.yml
- plugins/global-shortcut/**
tauri-plugin-http:
- .github/workflows/lint-rust.yml
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/lint-rust.yml
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/lint-rust.yml
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/lint-rust.yml
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/lint-rust.yml
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/lint-rust.yml
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/lint-rust.yml
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/lint-rust.yml
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/lint-rust.yml
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/lint-rust.yml
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/lint-rust.yml
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/lint-rust.yml
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/lint-rust.yml
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/lint-rust.yml
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/lint-rust.yml
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/lint-rust.yml
- plugins/websocket/**
tauri-plugin-window:
- .github/workflows/lint-rust.yml
- plugins/window/**
tauri-plugin-window-state:
- .github/workflows/lint-rust.yml
- plugins/window-state/**
clippy: clippy:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
runs-on: ubuntu-latest runs-on: ubuntu-latest
strategy: strategy:
fail-fast: false fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
steps: steps:
- uses: actions/checkout@v3 - uses: actions/checkout@v3
@ -43,17 +147,25 @@ jobs:
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: clippy - name: create dummy dist
run: cargo clippy --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features -- -D warnings working-directory: examples/api
run: mkdir dist
- name: clippy ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
- name: clippy sql:sqlite - name: clippy ${{ matrix.package }} --all-features
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features sqlite -- -D warnings if: ${{ !contains(fromJSON('["tauri-plugin-http", "tauri-plugin-upload", "tauri-plugin-updater", "tauri-plugin-websocket", "tauri-plugin-sql"]'), matrix.package) }}
run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
- name: clippy sql:mysql - name: clippy ${{ matrix.package }} mysql
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features mysql -- -D warnings if: matrix.package == 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features mysql -- -D warnings
- name: clippy sql:postgres - name: clippy ${{ matrix.package }} postgres
run: cargo clippy --package 'tauri-plugin-sql' --all-targets --features postgres -- -D warnings if: matrix.package == 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features postgres -- -D warnings
fmt: fmt:
runs-on: ubuntu-latest runs-on: ubuntu-latest

@ -1,55 +0,0 @@
name: Check MSRV
on:
push:
branches:
- v1
- v2
paths:
- ".github/workflows/msrv-check.yml"
- "plugins/*/src/**"
- "**/Cargo.toml"
- "**/Cargo.lock"
pull_request:
branches:
- v1
- v2
paths:
- ".github/workflows/msrv-check.yml"
- "plugins/*/src/**"
- "**/Cargo.toml"
- "**/Cargo.lock"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
msrv:
runs-on: ubuntu-latest
strategy:
fail-fast: false
steps:
- uses: actions/checkout@v3
- name: install webkit2gtk and libudev for [authenticator]
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- uses: dtolnay/rust-toolchain@1.64.0
- uses: Swatinem/rust-cache@v2
- name: build
run: cargo build --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features
- name: build sql:sqlite
run: cargo build --package 'tauri-plugin-sql' --all-targets --features sqlite
- name: build sql:mysql
run: cargo build --package 'tauri-plugin-sql' --all-targets --features mysql
- name: build sql:postgres
run: cargo build --package 'tauri-plugin-sql' --all-targets --features postgres

@ -1,3 +1,7 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Sync name: Sync
on: on:

@ -0,0 +1,226 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: Test Rust
on:
push:
branches:
- v1
- v2
paths:
- ".github/workflows/test-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
- "**/Cargo.lock"
pull_request:
branches:
- v1
- v2
paths:
- ".github/workflows/test-rust.yml"
- "plugins/*/src/**"
- "!plugins/*/src/api-iife.js"
- "**/Cargo.toml"
- "**/Cargo.lock"
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
changes:
runs-on: ubuntu-latest
permissions:
pull-requests: read
outputs:
packages: ${{ steps.filter.outputs.changes }}
steps:
- uses: actions/checkout@v3
- uses: dorny/paths-filter@v2
id: filter
with:
filters: |
tauri-plugin-app:
- .github/workflows/test-rust.yml
- plugins/app/**
tauri-plugin-authenticator:
- .github/workflows/test-rust.yml
- plugins/authenticator/**
tauri-plugin-autostart:
- .github/workflows/test-rust.yml
- plugins/autostart/**
tauri-plugin-cli:
- .github/workflows/test-rust.yml
- plugins/cli/**
tauri-plugin-clipboard-manager:
- .github/workflows/test-rust.yml
- plugins/clipboard-manager/**
tauri-plugin-dialog:
- .github/workflows/test-rust.yml
- plugins/dialog/**
- plugins/fs/**
tauri-plugin-fs:
- .github/workflows/test-rust.yml
- plugins/fs/**
tauri-plugin-global-shortcut:
- .github/workflows/test-rust.yml
- plugins/global-shortcut/**
tauri-plugin-http:
- .github/workflows/test-rust.yml
- plugins/http/**
- plugins/fs/**
tauri-plugin-localhost:
- .github/workflows/test-rust.yml
- plugins/localhost/**
tauri-plugin-log:
- .github/workflows/test-rust.yml
- plugins/log/**
tauri-plugin-notification:
- .github/workflows/test-rust.yml
- plugins/notification/**
tauri-plugin-os:
- .github/workflows/test-rust.yml
- plugins/os/**
tauri-plugin-persisted-scope:
- .github/workflows/test-rust.yml
- plugins/persisted-scope/**
- plugins/fs/**
tauri-plugin-positioner:
- .github/workflows/test-rust.yml
- plugins/positioner/**
tauri-plugin-process:
- .github/workflows/test-rust.yml
- plugins/process/**
tauri-plugin-shell:
- .github/workflows/test-rust.yml
- plugins/shell/**
tauri-plugin-single-instance:
- .github/workflows/test-rust.yml
- plugins/single-instance/**
tauri-plugin-sql:
- .github/workflows/test-rust.yml
- plugins/sql/**
tauri-plugin-store:
- .github/workflows/test-rust.yml
- plugins/store/**
tauri-plugin-stronghold:
- .github/workflows/test-rust.yml
- plugins/stronghold/**
tauri-plugin-updater:
- .github/workflows/test-rust.yml
- plugins/updater/**
tauri-plugin-upload:
- .github/workflows/test-rust.yml
- plugins/upload/**
tauri-plugin-websocket:
- .github/workflows/test-rust.yml
- plugins/websocket/**
tauri-plugin-window:
- .github/workflows/test-rust.yml
- plugins/window/**
tauri-plugin-window-state:
- .github/workflows/test-rust.yml
- plugins/window-state/**
test:
needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
strategy:
fail-fast: false
matrix:
package: ${{ fromJSON(needs.changes.outputs.packages) }}
platform:
- {
target: x86_64-pc-windows-msvc,
os: windows-latest,
cross: false,
command: "test",
}
- {
target: x86_64-unknown-linux-gnu,
os: ubuntu-latest,
cross: false,
command: "test",
}
- {
target: x86_64-apple-darwin,
os: macos-latest,
cross: false,
command: "test",
}
- {
target: aarch64-apple-ios,
os: macos-latest,
cross: false,
command: "build",
}
- {
target: aarch64-linux-android,
os: ubuntu-latest,
cross: true,
command: "build",
}
runs-on: ${{ matrix.platform.os }}
steps:
- uses: actions/checkout@v3
- name: install webkit2gtk and libudev for [authenticator]
if: contains(matrix.platform.target, 'unknown-linux')
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: install openssl
if: ${{ matrix.platform.os == 'windows-latest' && matrix.package == 'tauri-plugin-authenticator' }}
run: |
echo "VCPKG_ROOT=$env:VCPKG_INSTALLATION_ROOT" | Out-File -FilePath $env:GITHUB_ENV -Append
vcpkg install openssl:x64-windows-static-md
- uses: dtolnay/rust-toolchain@1.65.0
with:
targets: ${{ matrix.platform.target }}
- uses: Swatinem/rust-cache@v2
with:
key: ${{ matrix.package }}
- name: create dummy dist
working-directory: examples/api
run: mkdir dist
- name: test ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
- name: test ${{ matrix.package }} --all-features
if: ${{ !contains(fromJSON('["tauri-plugin-http", "tauri-plugin-upload", "tauri-plugin-updater", "tauri-plugin-websocket", "tauri-plugin-sql"]'), matrix.package) }}
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
- name: test ${{ matrix.package }} mysql
if: matrix.package == 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features mysql
- name: test ${{ matrix.package }} postgres
if: matrix.package == 'tauri-plugin-sql'
uses: actions-rs/cargo@v1
with:
use-cross: ${{ matrix.platform.cross }}
command: ${{ matrix.platform.command }}
args: --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features postgres

@ -0,0 +1 @@
auto-install-peers=true

@ -1,5 +1,8 @@
target target
node_modules node_modules
dist dist
dist-js
pnpm-lock.yaml pnpm-lock.yaml
Cargo.lock Cargo.lock
.build
api-iife.js

@ -0,0 +1,121 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import fs from "fs";
import path from "path";
import readline from "readline";
const header = `Copyright 2019-2023 Tauri Programme within The Commons Conservancy
SPDX-License-Identifier: Apache-2.0
SPDX-License-Identifier: MIT`;
const ignoredLicense = "// Copyright 2021 Jonas Kruckenberg";
const extensions = [".rs", ".js", ".ts", ".yml", ".swift", ".kt"];
const ignore = [
"target",
"templates",
"node_modules",
"gen",
"dist",
"dist-js",
".svelte-kit",
"api-iife.js",
];
async function checkFile(file) {
if (
extensions.some((e) => file.endsWith(e)) &&
!ignore.some((i) => file.endsWith(i))
) {
const fileStream = fs.createReadStream(file);
const rl = readline.createInterface({
input: fileStream,
crlfDelay: Infinity,
});
let contents = ``;
let i = 0;
for await (let line of rl) {
// ignore empty lines, allow shebang, swift-tools-version and bundler license
if (
line.length === 0 ||
line.startsWith("#!") ||
line.startsWith("// swift-tools-version:") ||
line === ignoredLicense
) {
continue;
}
// strip comment marker
if (line.startsWith("// ")) {
line = line.substring(3);
} else if (line.startsWith("# ")) {
line = line.substring(2);
}
contents += line;
if (++i === 3) {
break;
}
contents += "\n";
}
if (contents !== header) {
return true;
}
}
return false;
}
async function check(src) {
const missingHeader = [];
for (const entry of fs.readdirSync(src, { withFileTypes: true })) {
const p = path.join(src, entry.name);
if (entry.isSymbolicLink() || ignore.includes(entry.name)) {
continue;
}
if (entry.isDirectory()) {
const missing = await check(p);
missingHeader.push(...missing);
} else {
const isMissing = await checkFile(p);
if (isMissing) {
missingHeader.push(p);
}
}
}
return missingHeader;
}
const [_bin, _script, ...files] = process.argv;
if (files.length > 0) {
async function run() {
const missing = [];
for (const f of files) {
const isMissing = await checkFile(f);
if (isMissing) {
missing.push(f);
}
}
if (missing.length > 0) {
console.log(missing.join("\n"));
process.exit(1);
}
}
run();
} else {
check(path.resolve(new URL(import.meta.url).pathname, "../../..")).then(
(missing) => {
if (missing.length > 0) {
console.log(missing.join("\n"));
process.exit(1);
}
}
);
}

@ -0,0 +1,9 @@
#!/bin/bash
if git diff --quiet --ignore-submodules HEAD
then
echo "working directory is clean"
else
echo "found diff"
exit 1
fi

@ -44,10 +44,14 @@ https.get(url, options, (response) => {
response.on("end", function () { response.on("end", function () {
const data = JSON.parse(chunks.join("")); const data = JSON.parse(chunks.join(""));
if (kind === "cargo") { if (kind === "cargo") {
const versions = data.versions.filter((v) => v.num.startsWith(target)); if (data.versions) {
console.log(versions.length ? versions[0].num : "0.0.0"); const versions = data.versions.filter((v) => v.num.startsWith(target));
console.log(versions.length ? versions[0].num : "0.0.0");
} else {
console.log("0.0.0");
}
} else if (kind === "npm") { } else if (kind === "npm") {
const versions = Object.keys(data.versions).filter((v) => const versions = Object.keys(data.versions || {}).filter((v) =>
v.startsWith(target) v.startsWith(target)
); );
console.log(versions[versions.length - 1] || "0.0.0"); console.log(versions[versions.length - 1] || "0.0.0");

726
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -1,13 +1,12 @@
[workspace] [workspace]
members = ["plugins/*", "examples/*/src-tauri"] members = ["plugins/*", "plugins/*/tests/*", "examples/*/src-tauri"]
exclude = ["plugins/fs", "plugins/http", "examples/api/src-tauri"]
resolver = "2" resolver = "2"
[workspace.dependencies] [workspace.dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
log = "0.4" log = "0.4"
tauri = "2.0.0-alpha.8" tauri = "2.0.0-alpha.9"
tauri-build = "2.0.0-alpha.4" tauri-build = "2.0.0-alpha.5"
serde_json = "1" serde_json = "1"
thiserror = "1" thiserror = "1"
@ -15,4 +14,12 @@ thiserror = "1"
edition = "2021" edition = "2021"
authors = [ "Tauri Programme within The Commons Conservancy" ] authors = [ "Tauri Programme within The Commons Conservancy" ]
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
rust-version = "1.64" rust-version = "1.65"
# default to small, optimized release binaries
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
incremental = false
opt-level = "s"

@ -1,21 +1,19 @@
## Plugins Found Here ## Plugins Found Here
| | | Win | Mac | Lin | iOS | And | | | | Win | Mac | Lin | iOS | And |
| ------------------------------------------ | --------------------------------------------------------- | --- | --- | --- | --- | --- | | ------------------------------------------ | ------------------------------------------------------ | --- | --- | --- | --- | --- |
| [authenticator](plugins/authenticator) | Interface with hardware security keys. | ✅ | ✅ | ✅ | ? | ? | | [authenticator](plugins/authenticator) | Interface with hardware security keys. | ✅ | ✅ | ✅ | ? | ? |
| [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ? | ? | | [autostart](plugins/autostart) | Automatically launch your app at system startup. | ✅ | ✅ | ✅ | ? | ? |
| [fs-extra](plugins/fs-extra) | File system methods that aren't included in the core API. | ✅ | ✅ | ✅ | ? | ? | | [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? |
| [fs-watch](plugins/fs-watch) | Watch the filesystem for changes. | ✅ | ✅ | ✅ | ? | ? | | [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ |
| [localhost](plugins/localhost) | Use a localhost server in production apps. | ✅ | ✅ | ✅ | ? | ? | | [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? |
| [log](plugins/log) | Configurable logging. | ✅ | ✅ | ✅ | ✅ | ✅ | | [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ? | ? |
| [persisted-scope](plugins/persisted-scope) | Persist runtime scope changes on the filesystem. | ✅ | ✅ | ✅ | ? | ? | | [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ? | ✅ | ? | ? |
| [positioner](plugins/positioner) | Move windows to common locations. | ✅ | ✅ | ✅ | ? | ? | | [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | ? |
| [single-instance](plugins/single-instance) | Ensure a single instance of your tauri app is running. | ✅ | ? | ✅ | ? | ? | | [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ? | ? |
| [sql](plugins/sql) | Interface with SQL databases. | ✅ | ✅ | ✅ | ? | ? | | [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? |
| [store](plugins/store) | Persistent key value storage. | ✅ | ✅ | ✅ | ? | ? | | [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? |
| [stronghold](plugins/stronghold) | Encrypted, secure database. | ✅ | ✅ | ✅ | ? | ? | | [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
| [upload](plugins/upload) | Tauri plugin for file uploads through HTTP. | ✅ | ✅ | ✅ | ? | ? | | [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ? | ? |
| [websocket](plugins/websocket) | Open a WebSocket connection using a Rust client in JS. | ✅ | ✅ | ✅ | ? | ? |
| [window-state](plugins/window-state) | Persist window sizes and positions. | ✅ | ✅ | ✅ | ? | ? |
_This repo and all plugins require a Rust version of at least **1.64**_ _This repo and all plugins require a Rust version of at least **1.65**_

@ -1,4 +1,7 @@
#!/usr/bin/env bash #!/usr/bin/env bash
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
export ICONS_VOLUME="$(realpath icons)" export ICONS_VOLUME="$(realpath icons)"
export DIST_VOLUME="$(realpath dist)" export DIST_VOLUME="$(realpath dist)"

@ -0,0 +1,7 @@
# Changelog
## \[2.0.0-alpha.0]
### Dependencies
- Plugins v2 alpha.

@ -1,6 +1,7 @@
{ {
"name": "svelte-app", "name": "svelte-app",
"version": "1.0.0", "private": true,
"version": "2.0.0-alpha.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --clearScreen false", "dev": "vite --clearScreen false",
@ -8,23 +9,28 @@
"serve": "vite preview" "serve": "vite preview"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.0.0-alpha.3", "@tauri-apps/api": "2.0.0-alpha.4",
"@tauri-apps/cli": "2.0.0-alpha.8",
"@zerodevx/svelte-json-view": "0.2.1", "@zerodevx/svelte-json-view": "0.2.1",
"tauri-plugin-barcode-scanner-api": "0.0.0", "@tauri-apps/plugin-app": "2.0.0-alpha.0",
"tauri-plugin-cli-api": "0.0.0", "@tauri-apps/plugin-barcode-scanner": "0.0.0",
"tauri-plugin-clipboard-api": "0.0.0", "@tauri-apps/plugin-cli": "2.0.0-alpha.0",
"tauri-plugin-dialog-api": "0.0.0", "@tauri-apps/plugin-clipboard-manager": "2.0.0-alpha.0",
"tauri-plugin-fs-api": "0.0.0", "@tauri-apps/plugin-dialog": "2.0.0-alpha.0",
"tauri-plugin-global-shortcut-api": "0.0.0", "@tauri-apps/plugin-fs": "2.0.0-alpha.0",
"tauri-plugin-http-api": "0.0.0", "@tauri-apps/plugin-global-shortcut": "2.0.0-alpha.0",
"tauri-plugin-notification-api": "0.0.0", "@tauri-apps/plugin-http": "2.0.0-alpha.0",
"tauri-plugin-shell-api": "0.0.0" "@tauri-apps/plugin-notification": "2.0.0-alpha.0",
"@tauri-apps/plugin-os": "2.0.0-alpha.0",
"@tauri-apps/plugin-process": "2.0.0-alpha.0",
"@tauri-apps/plugin-shell": "2.0.0-alpha.0",
"@tauri-apps/plugin-updater": "2.0.0-alpha.0",
"@tauri-apps/plugin-window": "2.0.0-alpha.0"
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/codicon": "^1.1.10", "@iconify-json/codicon": "^1.1.10",
"@iconify-json/ph": "^1.1.1", "@iconify-json/ph": "^1.1.1",
"@sveltejs/vite-plugin-svelte": "^1.0.1", "@sveltejs/vite-plugin-svelte": "^1.0.1",
"@tauri-apps/cli": "2.0.0-alpha.9",
"internal-ip": "^7.0.0", "internal-ip": "^7.0.0",
"svelte": "^3.49.0", "svelte": "^3.49.0",
"unocss": "^0.39.3", "unocss": "^0.39.3",

@ -0,0 +1,13 @@
# Changelog
## \[2.0.0-alpha.1]
### Dependencies
- Updated to latest `notification`
## \[2.0.0-alpha.0]
### Dependencies
- Plugins v2 alpha.

File diff suppressed because it is too large Load Diff

@ -1,49 +1,50 @@
[package] [package]
name = "api" name = "api"
version = "0.1.0" publish = false
version = "2.0.0-alpha.1"
description = "An example Tauri Application showcasing the api" description = "An example Tauri Application showcasing the api"
edition = "2021" edition = "2021"
rust-version = "1.64" rust-version = "1.65"
license = "Apache-2.0 OR MIT" license = "Apache-2.0 OR MIT"
[lib] [lib]
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = [ "staticlib", "cdylib", "rlib" ]
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.0.0-alpha.4", features = ["codegen", "isolation"] } tauri-build = { workspace = true, features = [ "codegen", "isolation" ] }
[dependencies] [dependencies]
serde_json = "1.0" serde_json = { workspace = true }
serde = { version = "1.0", features = [ "derive" ] } serde = { workspace = true }
tiny_http = "0.11" tiny_http = "0.11"
log = "0.4" log = { workspace = true }
tauri-plugin-log = { path = "../../../plugins/log" } tauri-plugin-app = { path = "../../../plugins/app", version = "2.0.0-alpha.0" }
tauri-plugin-fs = { path = "../../../plugins/fs" } tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.0-alpha.0" }
tauri-plugin-clipboard = { path = "../../../plugins/clipboard" } tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.0-alpha.0" }
tauri-plugin-dialog = { path = "../../../plugins/dialog" } tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.0-alpha.0" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ "http-multipart" ] } tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-alpha.0" }
tauri-plugin-notification = { path = "../../../plugins/notification", features = [ "windows7-compat" ] } tauri-plugin-http = { path = "../../../plugins/http", features = [ "multipart" ], version = "2.0.0-alpha.0" }
tauri-plugin-shell = { path = "../../../plugins/shell" } tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-alpha.0", features = [ "windows7-compat" ] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-alpha.0" }
[patch.crates-io] tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-alpha.0" }
tauri = { git = "https://github.com/tauri-apps/tauri", branch = "next" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-alpha.0" }
tauri-build = { git = "https://github.com/tauri-apps/tauri", branch = "next" } tauri-plugin-window = { path = "../../../plugins/window", version = "2.0.0-alpha.0", features = [ "devtools", "icon-ico", "icon-png" ] }
[dependencies.tauri] [dependencies.tauri]
version = "2.0.0-alpha.8" workspace = true
features = [ features = [
"api-all",
"icon-ico", "icon-ico",
"icon-png", "icon-png",
"isolation", "isolation",
"macos-private-api", "macos-private-api",
"system-tray", "system-tray",
"updater" "protocol-asset"
] ]
[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" } tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.0.0-alpha.0" }
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut" } tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.0.0-alpha.0" }
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-alpha.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" } tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner" }
@ -53,11 +54,3 @@ window-shadows = "0.2"
[features] [features]
custom-protocol = [ "tauri/custom-protocol" ] custom-protocol = [ "tauri/custom-protocol" ]
# default to small, optimized release binaries
[profile.release]
panic = "abort"
codegen-units = 1
lto = true
incremental = false
opt-level = "s"

@ -3,10 +3,10 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
fn main() { fn main() {
let mut codegen = tauri_build::CodegenContext::new(); let mut codegen = tauri_build::CodegenContext::new();
if !cfg!(feature = "custom-protocol") { if !cfg!(feature = "custom-protocol") {
codegen = codegen.dev(); codegen = codegen.dev();
} }
codegen.build(); codegen.build();
tauri_build::build(); tauri_build::build();
} }

@ -8,6 +8,7 @@ build
.externalNativeBuild .externalNativeBuild
.cxx .cxx
local.properties local.properties
key.properties
/.tauri /.tauri
/tauri.settings.gradle /tauri.settings.gradle

@ -1,113 +0,0 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rustPlugin")
}
android {
compileSdk = 33
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
sourceSets.getByName("main") {
// Vulkan validation layers
val ndkHome = System.getenv("NDK_HOME")
jniLibs.srcDir("${ndkHome}/sources/third_party/vulkan/src/build-android/jniLibs")
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packagingOptions { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
val proguards = fileTree(".") {
include("*.pro")
}
proguardFiles(*proguards.toList().toTypedArray())
}
}
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += (findProperty("abiList") as? String)?.split(",") ?: listOf( "arm64-v8a", "armeabi-v7a", "x86", "x86_64",
)
}
}
create("arm64") {
dimension = "abi"
ndk {
abiFilters += listOf("arm64-v8a")
}
}
create("arm") {
dimension = "abi"
ndk {
abiFilters += listOf("armeabi-v7a")
}
}
create("x86") {
dimension = "abi"
ndk {
abiFilters += listOf("x86")
}
}
create("x86_64") {
dimension = "abi"
ndk {
abiFilters += listOf("x86_64")
}
}
}
assetPacks += mutableSetOf()
namespace = "com.tauri.api"
}
rust {
rootDirRel = "../../../../"
targets = (findProperty("targetList") as? String)?.split(",") ?: listOf("aarch64", "armv7", "i686", "x86_64")
arches = (findProperty("archList") as? String)?.split(",") ?: listOf("arm64", "arm", "x86", "x86_64")
}
dependencies {
implementation("androidx.webkit:webkit:1.5.0")
implementation("androidx.appcompat:appcompat:1.5.1")
implementation("com.google.android.material:material:1.7.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
implementation(project(":tauri-android"))
}
apply(from = "tauri.build.gradle.kts")
afterEvaluate {
android.applicationVariants.all {
tasks["mergeUniversalReleaseJniLibFolders"].dependsOn(tasks["rustBuildRelease"])
tasks["mergeUniversalDebugJniLibFolders"].dependsOn(tasks["rustBuildDebug"])
if (findProperty("targetList") == null) {
productFlavors.filter{ it.name != "universal" }.forEach { _ ->
val archAndBuildType = name.capitalize()
tasks["merge${archAndBuildType}JniLibFolders"].dependsOn(tasks["rustBuild${archAndBuildType}"])
}
}
}
}

@ -1,4 +0,0 @@
package com.tauri.api
class MainActivity : TauriActivity() {
}

@ -1,25 +0,0 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
google()
mavenCentral()
}
dependencies {
classpath("com.android.tools.build:gradle:7.3.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean").configure {
delete("build")
}

@ -1,23 +0,0 @@
plugins {
`kotlin-dsl`
}
gradlePlugin {
plugins {
create("pluginsForCoolKids") {
id = "rustPlugin"
implementationClass = "com.tauri.RustPlugin"
}
}
}
repositories {
google()
mavenCentral()
}
dependencies {
compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:7.3.1")
}

@ -1,59 +0,0 @@
package com.tauri
import org.gradle.api.DefaultTask
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import java.io.File
import java.util.*
const val TASK_GROUP = "rust"
open class Config {
var rootDirRel: String? = null
var targets: List<String>? = null
var arches: List<String>? = null
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) {
config = project.extensions.create("rust", Config::class.java)
project.afterEvaluate {
if (config.targets == null) {
throw GradleException("targets cannot be null")
}
if (config.arches == null) {
throw GradleException("arches cannot be null")
}
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.capitalize(Locale.ROOT)
val buildTask = project.tasks.maybeCreate(
"rustBuild$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
for (targetPair in config.targets!!.withIndex()) {
val targetName = targetPair.value
val targetArch = config.arches!![targetPair.index]
val targetArchCapitalized = targetArch.capitalize(Locale.ROOT)
val targetBuildTask = project.tasks.maybeCreate(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel?.let { File(it) }
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
project.tasks.findByName("preBuild")?.mustRunAfter(targetBuildTask)
}
}
}
}
}

@ -1,6 +0,0 @@
include ':app'
include ':tauri-android'
project(':tauri-android').projectDir = new File('./.tauri/tauri-api')
apply from: 'tauri.settings.gradle'

@ -1,4 +1,5 @@
/src/main/java/com/tauri/api/generated /src/main/java/com/tauri/api/generated
/src/main/jniLibs/**/*.so /src/main/jniLibs/**/*.so
/src/main/assets/tauri.conf.json
/tauri.build.gradle.kts /tauri.build.gradle.kts
/proguard-tauri.pro /proguard-tauri.pro

@ -0,0 +1,57 @@
plugins {
id("com.android.application")
id("org.jetbrains.kotlin.android")
id("rust")
}
android {
compileSdk = 33
namespace = "com.tauri.api"
defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api"
minSdk = 24
targetSdk = 33
versionCode = 1
versionName = "1.0"
}
buildTypes {
getByName("debug") {
manifestPlaceholders["usesCleartextTraffic"] = "true"
isDebuggable = true
isJniDebuggable = true
isMinifyEnabled = false
packaging { jniLibs.keepDebugSymbols.add("*/arm64-v8a/*.so")
jniLibs.keepDebugSymbols.add("*/armeabi-v7a/*.so")
jniLibs.keepDebugSymbols.add("*/x86/*.so")
jniLibs.keepDebugSymbols.add("*/x86_64/*.so")
}
}
getByName("release") {
isMinifyEnabled = true
proguardFiles(
*fileTree(".") { include("**/*.pro") }
.plus(getDefaultProguardFile("proguard-android-optimize.txt"))
.toList().toTypedArray()
)
}
}
kotlinOptions {
jvmTarget = "1.8"
}
}
rust {
rootDirRel = "../../../"
}
dependencies {
implementation("androidx.webkit:webkit:1.6.1")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("com.google.android.material:material:1.8.0")
testImplementation("junit:junit:4.13.2")
androidTestImplementation("androidx.test.ext:junit:1.1.4")
androidTestImplementation("androidx.test.espresso:espresso-core:3.5.0")
}
apply(from = "tauri.build.gradle.kts")

@ -14,7 +14,6 @@
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>

@ -0,0 +1,3 @@
package com.tauri.api
class MainActivity : TauriActivity()

@ -1,14 +1,11 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript { buildscript {
repositories { repositories {
google() google()
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:7.3.1") classpath("com.android.tools.build:gradle:8.0.0")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21")
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
} }
} }

@ -5,8 +5,8 @@ plugins {
gradlePlugin { gradlePlugin {
plugins { plugins {
create("pluginsForCoolKids") { create("pluginsForCoolKids") {
id = "rustPlugin" id = "rust"
implementationClass = "app.tauri.RustPlugin" implementationClass = "RustPlugin"
} }
} }
} }
@ -18,6 +18,6 @@ repositories {
dependencies { dependencies {
compileOnly(gradleApi()) compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:7.3.1") implementation("com.android.tools.build:gradle:8.0.0")
} }

@ -1,28 +1,22 @@
package com.tauri
import java.io.File import java.io.File
import org.apache.tools.ant.taskdefs.condition.Os import org.apache.tools.ant.taskdefs.condition.Os
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.logging.LogLevel import org.gradle.api.logging.LogLevel
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputDirectory
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.api.tasks.TaskAction import org.gradle.api.tasks.TaskAction
open class BuildTask : DefaultTask() { open class BuildTask : DefaultTask() {
@InputDirectory @Input
@PathSensitive(PathSensitivity.RELATIVE) var rootDirRel: String? = null
var rootDirRel: File? = null
@Input @Input
var target: String? = null var target: String? = null
@Input @Input
var release: Boolean? = null var release: Boolean? = null
@TaskAction @TaskAction
fun build() { fun assemble() {
val executable = """yarn"""; val executable = """pnpm""";
try { try {
runTauriCli(executable) runTauriCli(executable)
} catch (e: Exception) { } catch (e: Exception) {
@ -41,7 +35,7 @@ open class BuildTask : DefaultTask() {
val args = listOf("tauri", "android", "android-studio-script"); val args = listOf("tauri", "android", "android-studio-script");
project.exec { project.exec {
workingDir(File(project.projectDir, rootDirRel.path)) workingDir(File(project.projectDir, rootDirRel))
executable(executable) executable(executable)
args(args) args(args)
if (project.logger.isEnabled(LogLevel.DEBUG)) { if (project.logger.isEnabled(LogLevel.DEBUG)) {

@ -0,0 +1,85 @@
import com.android.build.api.dsl.ApplicationExtension
import org.gradle.api.DefaultTask
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.kotlin.dsl.configure
import org.gradle.kotlin.dsl.get
const val TASK_GROUP = "rust"
open class Config {
lateinit var rootDirRel: String
}
open class RustPlugin : Plugin<Project> {
private lateinit var config: Config
override fun apply(project: Project) = with(project) {
config = extensions.create("rust", Config::class.java)
val defaultAbiList = listOf("arm64-v8a", "armeabi-v7a", "x86", "x86_64");
val abiList = (findProperty("abiList") as? String)?.split(',') ?: defaultAbiList
val defaultArchList = listOf("arm64", "arm", "x86", "x86_64");
val archList = (findProperty("archList") as? String)?.split(',') ?: defaultArchList
val targetsList = (findProperty("targetList") as? String)?.split(',') ?: listOf("aarch64", "armv7", "i686", "x86_64")
extensions.configure<ApplicationExtension> {
@Suppress("UnstableApiUsage")
flavorDimensions.add("abi")
productFlavors {
create("universal") {
dimension = "abi"
ndk {
abiFilters += abiList
}
}
defaultArchList.forEachIndexed { index, arch ->
create(arch) {
dimension = "abi"
ndk {
abiFilters.add(defaultAbiList[index])
}
}
}
}
}
afterEvaluate {
for (profile in listOf("debug", "release")) {
val profileCapitalized = profile.replaceFirstChar { it.uppercase() }
val buildTask = tasks.maybeCreate(
"rustBuildUniversal$profileCapitalized",
DefaultTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for all targets"
}
tasks["mergeUniversal${profileCapitalized}JniLibFolders"].dependsOn(buildTask)
for (targetPair in targetsList.withIndex()) {
val targetName = targetPair.value
val targetArch = archList[targetPair.index]
val targetArchCapitalized = targetArch.replaceFirstChar { it.uppercase() }
val targetBuildTask = project.tasks.maybeCreate(
"rustBuild$targetArchCapitalized$profileCapitalized",
BuildTask::class.java
).apply {
group = TASK_GROUP
description = "Build dynamic library in $profile mode for $targetArch"
rootDirRel = config.rootDirRel
target = targetName
release = profile == "release"
}
buildTask.dependsOn(targetBuildTask)
tasks["merge$targetArchCapitalized${profileCapitalized}JniLibFolders"].dependsOn(
targetBuildTask
)
}
}
}
}
}

@ -20,4 +20,6 @@ kotlin.code.style=official
# Enables namespacing of each library's R class so that its R class includes only the # Enables namespacing of each library's R class so that its R class includes only the
# resources declared in the library itself and none from the library's dependencies, # resources declared in the library itself and none from the library's dependencies,
# thereby reducing the size of the R class for that library # thereby reducing the size of the R class for that library
android.nonTransitiveRClass=true android.nonTransitiveRClass=true
android.defaults.buildfeatures.buildconfig=true
android.nonFinalResIds=false

@ -1,6 +1,6 @@
#Tue May 10 19:22:52 CST 2022 #Tue May 10 19:22:52 CST 2022
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

@ -0,0 +1,3 @@
include ':app'
apply from: 'tauri.settings.gradle'

@ -31,12 +31,16 @@ pub fn run() {
.level(log::LevelFilter::Info) .level(log::LevelFilter::Info)
.build(), .build(),
) )
.plugin(tauri_plugin_app::init())
.plugin(tauri_plugin_fs::init()) .plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_clipboard::init()) .plugin(tauri_plugin_clipboard_manager::init())
.plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_http::init()) .plugin(tauri_plugin_http::init())
.plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_window::init())
.setup(move |app| { .setup(move |app| {
#[cfg(desktop)] #[cfg(desktop)]
{ {
@ -44,6 +48,8 @@ pub fn run() {
app.handle().plugin(tauri_plugin_cli::init())?; app.handle().plugin(tauri_plugin_cli::init())?;
app.handle() app.handle()
.plugin(tauri_plugin_global_shortcut::Builder::new().build())?; .plugin(tauri_plugin_global_shortcut::Builder::new().build())?;
app.handle()
.plugin(tauri_plugin_updater::Builder::new().build())?;
} }
#[cfg(mobile)] #[cfg(mobile)]

@ -46,6 +46,45 @@
] ]
} }
} }
},
"fs": {
"scope": {
"allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
},
"shell": {
"open": true,
"scope": [
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"http": {
"scope": ["http://localhost:3003"]
},
"updater": {
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
} }
}, },
"tauri": { "tauri": {
@ -75,57 +114,10 @@
} }
} }
} }
}
},
"updater": {
"active": true,
"pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK",
"endpoints": [
"https://tauri-update-server.vercel.app/update/{{target}}/{{current_version}}"
]
},
"allowlist": {
"all": true,
"fs": {
"scope": {
"allow": ["$APPDATA/db/**", "$DOWNLOAD/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
}, },
"shell": { "updater": {
"open": true, "active": true,
"scope": [ "pubkey": "dW50cnVzdGVkIGNvbW1lbnQ6IG1pbmlzaWduIHB1YmxpYyBrZXk6IDE5QzMxNjYwNTM5OEUwNTgKUldSWTRKaFRZQmJER1h4d1ZMYVA3dnluSjdpN2RmMldJR09hUFFlZDY0SlFqckkvRUJhZDJVZXAK"
{
"name": "sh",
"cmd": "sh",
"args": [
"-c",
{
"validator": "\\S+"
}
]
},
{
"name": "cmd",
"cmd": "cmd",
"args": [
"/C",
{
"validator": "\\S+"
}
]
}
]
},
"protocol": {
"asset": true,
"assetScope": {
"allow": ["$APPDATA/db/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
},
"http": {
"scope": ["http://localhost:3003"]
} }
}, },
"windows": [], "windows": [],
@ -136,7 +128,14 @@
"img-src": "'self' asset: https://asset.localhost blob: data:", "img-src": "'self' asset: https://asset.localhost blob: data:",
"style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com" "style-src": "'unsafe-inline' 'self' https://fonts.googleapis.com"
}, },
"freezePrototype": true "freezePrototype": true,
"assetProtocol": {
"enable": true,
"scope": {
"allow": ["$APPDATA/db/**", "$RESOURCE/**"],
"deny": ["$APPDATA/db/*.stronghold"]
}
}
}, },
"systemTray": { "systemTray": {
"iconPath": "icons/tray_icon_with_transparency.png", "iconPath": "icons/tray_icon_with_transparency.png",

@ -1,191 +1,191 @@
<script> <script>
import { writable } from 'svelte/store' import { writable } from "svelte/store";
import { open } from 'tauri-plugin-shell-api' import { open } from "@tauri-apps/plugin-shell";
import { appWindow, getCurrent } from '@tauri-apps/api/window' import { appWindow, getCurrent } from "@tauri-apps/plugin-window";
import * as os from '@tauri-apps/api/os' import * as os from "@tauri-apps/plugin-os";
import Welcome from './views/Welcome.svelte' import Welcome from "./views/Welcome.svelte";
import Cli from './views/Cli.svelte' import Cli from "./views/Cli.svelte";
import Communication from './views/Communication.svelte' import Communication from "./views/Communication.svelte";
import Dialog from './views/Dialog.svelte' import Dialog from "./views/Dialog.svelte";
import FileSystem from './views/FileSystem.svelte' import FileSystem from "./views/FileSystem.svelte";
import Http from './views/Http.svelte' import Http from "./views/Http.svelte";
import Notifications from './views/Notifications.svelte' import Notifications from "./views/Notifications.svelte";
import Window from './views/Window.svelte' import Window from "./views/Window.svelte";
import Shortcuts from './views/Shortcuts.svelte' import Shortcuts from "./views/Shortcuts.svelte";
import Shell from './views/Shell.svelte' import Shell from "./views/Shell.svelte";
import Updater from './views/Updater.svelte' import Updater from "./views/Updater.svelte";
import Clipboard from './views/Clipboard.svelte' import Clipboard from "./views/Clipboard.svelte";
import WebRTC from './views/WebRTC.svelte' import WebRTC from "./views/WebRTC.svelte";
import Scanner from './views/Scanner.svelte' import Scanner from "./views/Scanner.svelte";
import App from './views/App.svelte' import App from "./views/App.svelte";
import { onMount } from 'svelte' import { onMount } from "svelte";
import { listen } from '@tauri-apps/api/event' import { ask } from "@tauri-apps/plugin-dialog";
import { ask } from 'tauri-plugin-dialog-api'
if (appWindow.label !== "main") {
if (appWindow.label !== 'main') {
appWindow.onCloseRequested(async (event) => { appWindow.onCloseRequested(async (event) => {
const confirmed = await confirm('Are you sure?') const confirmed = await confirm("Are you sure?");
if (!confirmed) { if (!confirmed) {
// user did not confirm closing the window; let's prevent it // user did not confirm closing the window; let's prevent it
event.preventDefault() event.preventDefault();
} }
}) });
} }
appWindow.onFileDropEvent((event) => { appWindow.onFileDropEvent((event) => {
onMessage(`File drop: ${JSON.stringify(event.payload)}`) onMessage(`File drop: ${JSON.stringify(event.payload)}`);
}) });
const userAgent = navigator.userAgent.toLowerCase() const userAgent = navigator.userAgent.toLowerCase();
const isMobile = userAgent.includes('android') || userAgent.includes('iphone') const isMobile =
userAgent.includes("android") || userAgent.includes("iphone");
const views = [ const views = [
{ {
label: 'Welcome', label: "Welcome",
component: Welcome, component: Welcome,
icon: 'i-ph-hand-waving' icon: "i-ph-hand-waving",
}, },
{ {
label: 'Communication', label: "Communication",
component: Communication, component: Communication,
icon: 'i-codicon-radio-tower' icon: "i-codicon-radio-tower",
}, },
!isMobile && { !isMobile && {
label: 'CLI', label: "CLI",
component: Cli, component: Cli,
icon: 'i-codicon-terminal' icon: "i-codicon-terminal",
}, },
!isMobile && { {
label: 'Dialog', label: "Dialog",
component: Dialog, component: Dialog,
icon: 'i-codicon-multiple-windows' icon: "i-codicon-multiple-windows",
}, },
{ {
label: 'File system', label: "File system",
component: FileSystem, component: FileSystem,
icon: 'i-codicon-files' icon: "i-codicon-files",
}, },
{ {
label: 'HTTP', label: "HTTP",
component: Http, component: Http,
icon: 'i-ph-globe-hemisphere-west' icon: "i-ph-globe-hemisphere-west",
}, },
!isMobile && { !isMobile && {
label: 'Notifications', label: "Notifications",
component: Notifications, component: Notifications,
icon: 'i-codicon-bell-dot' icon: "i-codicon-bell-dot",
}, },
!isMobile && { !isMobile && {
label: 'App', label: "App",
component: App, component: App,
icon: 'i-codicon-hubot' icon: "i-codicon-hubot",
}, },
!isMobile && { !isMobile && {
label: 'Window', label: "Window",
component: Window, component: Window,
icon: 'i-codicon-window' icon: "i-codicon-window",
}, },
!isMobile && { !isMobile && {
label: 'Shortcuts', label: "Shortcuts",
component: Shortcuts, component: Shortcuts,
icon: 'i-codicon-record-keys' icon: "i-codicon-record-keys",
}, },
{ {
label: 'Shell', label: "Shell",
component: Shell, component: Shell,
icon: 'i-codicon-terminal-bash' icon: "i-codicon-terminal-bash",
}, },
!isMobile && { !isMobile && {
label: 'Updater', label: "Updater",
component: Updater, component: Updater,
icon: 'i-codicon-cloud-download' icon: "i-codicon-cloud-download",
}, },
!isMobile && { !isMobile && {
label: 'Clipboard', label: "Clipboard",
component: Clipboard, component: Clipboard,
icon: 'i-codicon-clippy' icon: "i-codicon-clippy",
}, },
{ {
label: 'WebRTC', label: "WebRTC",
component: WebRTC, component: WebRTC,
icon: 'i-ph-broadcast' icon: "i-ph-broadcast",
}, },
isMobile && { isMobile && {
label: 'Scanner', label: "Scanner",
component: Scanner, component: Scanner,
icon: 'i-ph-scan' icon: "i-ph-scan",
} },
] ];
let selected = views[0] let selected = views[0];
function select(view) { function select(view) {
selected = view selected = view;
} }
// Window controls // Window controls
let isWindowMaximized let isWindowMaximized;
onMount(async () => { onMount(async () => {
const window = getCurrent() const window = getCurrent();
isWindowMaximized = await window.isMaximized() isWindowMaximized = await window.isMaximized();
listen('tauri://resize', async () => { window.onResized(async () => {
isWindowMaximized = await window.isMaximized() isWindowMaximized = await window.isMaximized();
}) });
}) });
function minimize() { function minimize() {
getCurrent().minimize() getCurrent().minimize();
} }
async function toggleMaximize() { async function toggleMaximize() {
const window = getCurrent() const window = getCurrent();
;(await window.isMaximized()) ? window.unmaximize() : window.maximize() (await window.isMaximized()) ? window.unmaximize() : window.maximize();
} }
let confirmed_close = false let confirmed_close = false;
async function close() { async function close() {
if (!confirmed_close) { if (!confirmed_close) {
confirmed_close = await ask( confirmed_close = await ask(
'Are you sure that you want to close this window?', "Are you sure that you want to close this window?",
{ {
title: 'Tauri API' title: "Tauri API",
} }
) );
if (confirmed_close) { if (confirmed_close) {
getCurrent().close() getCurrent().close();
} }
} }
} }
// dark/light // dark/light
let isDark let isDark;
onMount(() => { onMount(() => {
isDark = localStorage && localStorage.getItem('theme') == 'dark' isDark = localStorage && localStorage.getItem("theme") == "dark";
applyTheme(isDark) applyTheme(isDark);
}) });
function applyTheme(isDark) { function applyTheme(isDark) {
const html = document.querySelector('html') const html = document.querySelector("html");
isDark ? html.classList.add('dark') : html.classList.remove('dark') isDark ? html.classList.add("dark") : html.classList.remove("dark");
localStorage && localStorage.setItem('theme', isDark ? 'dark' : '') localStorage && localStorage.setItem("theme", isDark ? "dark" : "");
} }
function toggleDark() { function toggleDark() {
isDark = !isDark isDark = !isDark;
applyTheme(isDark) applyTheme(isDark);
} }
// Console // Console
let messages = writable([]) let messages = writable([]);
function onMessage(value) { function onMessage(value) {
messages.update((r) => [ messages.update((r) => [
{ {
html: html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` + `<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
(typeof value === 'string' ? value : JSON.stringify(value, null, 1)) + (typeof value === "string" ? value : JSON.stringify(value, null, 1)) +
'</pre>' "</pre>",
}, },
...r ...r,
]) ]);
} }
// this function is renders HTML without sanitizing it so it's insecure // this function is renders HTML without sanitizing it so it's insecure
@ -196,108 +196,110 @@
html: html:
`<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` + `<pre><strong class="text-accent dark:text-darkAccent">[${new Date().toLocaleTimeString()}]:</strong> ` +
html + html +
'</pre>' "</pre>",
}, },
...r ...r,
]) ]);
} }
function clear() { function clear() {
messages.update(() => []) messages.update(() => []);
} }
let consoleEl, consoleH, cStartY let consoleEl, consoleH, cStartY;
let minConsoleHeight = 50 let minConsoleHeight = 50;
function startResizingConsole(e) { function startResizingConsole(e) {
cStartY = e.clientY cStartY = e.clientY;
const styles = window.getComputedStyle(consoleEl) const styles = window.getComputedStyle(consoleEl);
consoleH = parseInt(styles.height, 10) consoleH = parseInt(styles.height, 10);
const moveHandler = (e) => { const moveHandler = (e) => {
const dy = e.clientY - cStartY const dy = e.clientY - cStartY;
const newH = consoleH - dy const newH = consoleH - dy;
consoleEl.style.height = `${ consoleEl.style.height = `${
newH < minConsoleHeight ? minConsoleHeight : newH newH < minConsoleHeight ? minConsoleHeight : newH
}px` }px`;
} };
const upHandler = () => { const upHandler = () => {
document.removeEventListener('mouseup', upHandler) document.removeEventListener("mouseup", upHandler);
document.removeEventListener('mousemove', moveHandler) document.removeEventListener("mousemove", moveHandler);
} };
document.addEventListener('mouseup', upHandler) document.addEventListener("mouseup", upHandler);
document.addEventListener('mousemove', moveHandler) document.addEventListener("mousemove", moveHandler);
} }
let isWindows let isWindows;
onMount(async () => { onMount(async () => {
isWindows = (await os.platform()) === 'win32' isWindows = (await os.platform()) === "win32";
}) });
// mobile // mobile
let isSideBarOpen = false let isSideBarOpen = false;
let sidebar let sidebar;
let sidebarToggle let sidebarToggle;
let isDraggingSideBar = false let isDraggingSideBar = false;
let draggingStartPosX = 0 let draggingStartPosX = 0;
let draggingEndPosX = 0 let draggingEndPosX = 0;
const clamp = (min, num, max) => Math.min(Math.max(num, min), max) const clamp = (min, num, max) => Math.min(Math.max(num, min), max);
function toggleSidebar(sidebar, isSideBarOpen) { function toggleSidebar(sidebar, isSideBarOpen) {
sidebar.style.setProperty( sidebar.style.setProperty(
'--translate-x', "--translate-x",
`${isSideBarOpen ? '0' : '-18.75'}rem` `${isSideBarOpen ? "0" : "-18.75"}rem`
) );
} }
onMount(() => { onMount(() => {
sidebar = document.querySelector('#sidebar') sidebar = document.querySelector("#sidebar");
sidebarToggle = document.querySelector('#sidebarToggle') sidebarToggle = document.querySelector("#sidebarToggle");
document.addEventListener('click', (e) => { document.addEventListener("click", (e) => {
if (sidebarToggle.contains(e.target)) { if (sidebarToggle.contains(e.target)) {
isSideBarOpen = !isSideBarOpen isSideBarOpen = !isSideBarOpen;
} else if (isSideBarOpen && !sidebar.contains(e.target)) { } else if (isSideBarOpen && !sidebar.contains(e.target)) {
isSideBarOpen = false isSideBarOpen = false;
} }
}) });
document.addEventListener('touchstart', (e) => { document.addEventListener("touchstart", (e) => {
if (sidebarToggle.contains(e.target)) return if (sidebarToggle.contains(e.target)) return;
const x = e.touches[0].clientX const x = e.touches[0].clientX;
if ((0 < x && x < 20 && !isSideBarOpen) || isSideBarOpen) { if ((0 < x && x < 20 && !isSideBarOpen) || isSideBarOpen) {
isDraggingSideBar = true isDraggingSideBar = true;
draggingStartPosX = x draggingStartPosX = x;
} }
}) });
document.addEventListener('touchmove', (e) => { document.addEventListener("touchmove", (e) => {
if (isDraggingSideBar) { if (isDraggingSideBar) {
const x = e.touches[0].clientX const x = e.touches[0].clientX;
draggingEndPosX = x draggingEndPosX = x;
const delta = (x - draggingStartPosX) / 10 const delta = (x - draggingStartPosX) / 10;
sidebar.style.setProperty( sidebar.style.setProperty(
'--translate-x', "--translate-x",
`-${clamp(0, isSideBarOpen ? 0 - delta : 18.75 - delta, 18.75)}rem` `-${clamp(0, isSideBarOpen ? 0 - delta : 18.75 - delta, 18.75)}rem`
) );
} }
}) });
document.addEventListener('touchend', () => { document.addEventListener("touchend", () => {
if (isDraggingSideBar) { if (isDraggingSideBar) {
const delta = (draggingEndPosX - draggingStartPosX) / 10 const delta = (draggingEndPosX - draggingStartPosX) / 10;
isSideBarOpen = isSideBarOpen ? delta > -(18.75 / 2) : delta > 18.75 / 2 isSideBarOpen = isSideBarOpen
? delta > -(18.75 / 2)
: delta > 18.75 / 2;
} }
isDraggingSideBar = false isDraggingSideBar = false;
}) });
}) });
$: { $: {
const sidebar = document.querySelector('#sidebar') const sidebar = document.querySelector("#sidebar");
if (sidebar) { if (sidebar) {
toggleSidebar(sidebar, isSideBarOpen) toggleSidebar(sidebar, isSideBarOpen);
} }
} }
</script> </script>
@ -316,7 +318,7 @@
children:items-center children:justify-center" children:items-center children:justify-center"
> >
<span <span
title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'} title={isDark ? "Switch to Light mode" : "Switch to Dark mode"}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleDark} on:click={toggleDark}
> >
@ -334,7 +336,7 @@
<div class="i-codicon-chrome-minimize" /> <div class="i-codicon-chrome-minimize" />
</span> </span>
<span <span
title={isWindowMaximized ? 'Restore' : 'Maximize'} title={isWindowMaximized ? "Restore" : "Maximize"}
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleMaximize} on:click={toggleMaximize}
> >
@ -346,7 +348,7 @@
</span> </span>
<span <span
title="Close" title="Close"
class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText " class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
on:click={close} on:click={close}
> >
<div class="i-codicon-chrome-close" /> <div class="i-codicon-chrome-close" />
@ -377,7 +379,7 @@
bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2" bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2"
> >
<img <img
on:click={() => open('https://tauri.app/')} on:click={() => open("https://tauri.app/")}
class="self-center p-7 cursor-pointer" class="self-center p-7 cursor-pointer"
src="tauri_logo.png" src="tauri_logo.png"
alt="Tauri logo" alt="Tauri logo"
@ -433,8 +435,8 @@
href="##" href="##"
class="nv {selected === view ? 'nv_selected' : ''}" class="nv {selected === view ? 'nv_selected' : ''}"
on:click={() => { on:click={() => {
select(view) select(view);
isSideBarOpen = false isSideBarOpen = false;
}} }}
> >
<div class="{view.icon} mr-2" /> <div class="{view.icon} mr-2" />

@ -1,24 +1,24 @@
<script> <script>
import { show, hide } from '@tauri-apps/api/app' import { show, hide } from "@tauri-apps/plugin-app";
export let onMessage export let onMessage;
function showApp() { function showApp() {
hideApp() hideApp()
.then(() => { .then(() => {
setTimeout(() => { setTimeout(() => {
show() show()
.then(() => onMessage('Shown app')) .then(() => onMessage("Shown app"))
.catch(onMessage) .catch(onMessage);
}, 2000) }, 2000);
}) })
.catch(onMessage) .catch(onMessage);
} }
function hideApp() { function hideApp() {
return hide() return hide()
.then(() => onMessage('Hide app')) .then(() => onMessage("Hide app"))
.catch(onMessage) .catch(onMessage);
} }
</script> </script>

@ -1,5 +1,5 @@
<script> <script>
import { getMatches } from "tauri-plugin-cli-api"; import { getMatches } from "@tauri-apps/plugin-cli";
export let onMessage; export let onMessage;

@ -1,23 +1,23 @@
<script> <script>
import { writeText, readText } from 'tauri-plugin-clipboard-api' import { writeText, readText } from "@tauri-apps/plugin-clipboard-manager";
export let onMessage export let onMessage;
let text = 'clipboard message' let text = "clipboard message";
function write() { function write() {
writeText(text) writeText(text)
.then(() => { .then(() => {
onMessage('Wrote to the clipboard') onMessage("Wrote to the clipboard");
}) })
.catch(onMessage) .catch(onMessage);
} }
function read() { function read() {
readText() readText()
.then((contents) => { .then((contents) => {
onMessage(`Clipboard contents: ${contents}`) onMessage(`Clipboard contents: ${contents}`);
}) })
.catch(onMessage) .catch(onMessage);
} }
</script> </script>

@ -1,41 +1,41 @@
<script> <script>
import { listen, emit } from '@tauri-apps/api/event' import { appWindow } from "@tauri-apps/plugin-window";
import { invoke } from '@tauri-apps/api/tauri' import { invoke } from "@tauri-apps/api/tauri";
import { onMount, onDestroy } from 'svelte' import { onMount, onDestroy } from "svelte";
export let onMessage export let onMessage;
let unlisten let unlisten;
onMount(async () => { onMount(async () => {
unlisten = await listen('rust-event', onMessage) unlisten = await appWindow.listen("rust-event", onMessage);
}) });
onDestroy(() => { onDestroy(() => {
if (unlisten) { if (unlisten) {
unlisten() unlisten();
} }
}) });
function log() { function log() {
invoke('log_operation', { invoke("log_operation", {
event: 'tauri-click', event: "tauri-click",
payload: 'this payload is optional because we used Option in Rust' payload: "this payload is optional because we used Option in Rust",
}) });
} }
function performRequest() { function performRequest() {
invoke('perform_request', { invoke("perform_request", {
endpoint: 'dummy endpoint arg', endpoint: "dummy endpoint arg",
body: { body: {
id: 5, id: 5,
name: 'test' name: "test",
} },
}) })
.then(onMessage) .then(onMessage)
.catch(onMessage) .catch(onMessage);
} }
function emitEvent() { function emitEvent() {
emit('js-event', 'this is the payload string') appWindow.emit("js-event", "this is the payload string");
} }
</script> </script>

@ -1,89 +1,102 @@
<script> <script>
import { open, save } from 'tauri-plugin-dialog-api' import { open, save, confirm } from "@tauri-apps/plugin-dialog";
import { readBinaryFile } from 'tauri-plugin-fs-api' import { readBinaryFile } from "@tauri-apps/plugin-fs";
export let onMessage export let onMessage;
export let insecureRenderHtml export let insecureRenderHtml;
let defaultPath = null let defaultPath = null;
let filter = null let filter = null;
let multiple = false let multiple = false;
let directory = false let directory = false;
function arrayBufferToBase64(buffer, callback) { function arrayBufferToBase64(buffer, callback) {
var blob = new Blob([buffer], { var blob = new Blob([buffer], {
type: 'application/octet-binary' type: "application/octet-binary",
}) });
var reader = new FileReader() var reader = new FileReader();
reader.onload = function (evt) { reader.onload = function (evt) {
var dataurl = evt.target.result var dataurl = evt.target.result;
callback(dataurl.substr(dataurl.indexOf(',') + 1)) callback(dataurl.substr(dataurl.indexOf(",") + 1));
} };
reader.readAsDataURL(blob) reader.readAsDataURL(blob);
}
async function prompt() {
confirm("Is Tauri awesome?", {
okLabel: "Absolutely",
cancelLabel: "Totally",
})
.then((res) =>
onMessage(
res ? "Tauri is absolutely awesome" : "Tauri is totally awesome"
)
)
.catch(onMessage);
} }
function openDialog() { function openDialog() {
open({ open({
title: 'My wonderful open dialog', title: "My wonderful open dialog",
defaultPath, defaultPath,
filters: filter filters: filter
? [ ? [
{ {
name: 'Tauri Example', name: "Tauri Example",
extensions: filter.split(',').map((f) => f.trim()) extensions: filter.split(",").map((f) => f.trim()),
} },
] ]
: [], : [],
multiple, multiple,
directory directory,
}) })
.then(function (res) { .then(function (res) {
if (Array.isArray(res)) { if (Array.isArray(res)) {
onMessage(res) onMessage(res);
} else { } else {
var pathToRead = typeof res === 'string' ? res : res.path var pathToRead = typeof res === "string" ? res : res.path;
var isFile = pathToRead.match(/\S+\.\S+$/g) var isFile = pathToRead.match(/\S+\.\S+$/g);
readBinaryFile(pathToRead) readBinaryFile(pathToRead)
.then(function (response) { .then(function (response) {
if (isFile) { if (isFile) {
if ( if (
pathToRead.includes('.png') || pathToRead.includes(".png") ||
pathToRead.includes('.jpg') pathToRead.includes(".jpg")
) { ) {
arrayBufferToBase64( arrayBufferToBase64(
new Uint8Array(response), new Uint8Array(response),
function (base64) { function (base64) {
var src = 'data:image/png;base64,' + base64 var src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>') insecureRenderHtml('<img src="' + src + '"></img>');
} }
) );
} else { } else {
onMessage(res) onMessage(res);
} }
} else { } else {
onMessage(res) onMessage(res);
} }
}) })
.catch(onMessage(res)) .catch(onMessage(res));
} }
}) })
.catch(onMessage) .catch(onMessage);
} }
function saveDialog() { function saveDialog() {
save({ save({
title: 'My wonderful save dialog', title: "My wonderful save dialog",
defaultPath, defaultPath,
filters: filter filters: filter
? [ ? [
{ {
name: 'Tauri Example', name: "Tauri Example",
extensions: filter.split(',').map((f) => f.trim()) extensions: filter.split(",").map((f) => f.trim()),
} },
] ]
: [] : [],
}) })
.then(onMessage) .then(onMessage)
.catch(onMessage) .catch(onMessage);
} }
</script> </script>
@ -116,3 +129,4 @@
<button class="btn" id="save-dialog" on:click={saveDialog} <button class="btn" id="save-dialog" on:click={saveDialog}
>Open save dialog</button >Open save dialog</button
> >
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>

@ -3,79 +3,79 @@
readBinaryFile, readBinaryFile,
writeTextFile, writeTextFile,
readDir, readDir,
Dir Dir,
} from 'tauri-plugin-fs-api' } from "@tauri-apps/plugin-fs";
import { convertFileSrc } from '@tauri-apps/api/tauri' import { convertFileSrc } from "@tauri-apps/api/tauri";
export let onMessage export let onMessage;
export let insecureRenderHtml export let insecureRenderHtml;
let pathToRead = '' let pathToRead = "";
let img let img;
function getDir() { function getDir() {
const dirSelect = document.getElementById('dir') const dirSelect = document.getElementById("dir");
return dirSelect.value ? parseInt(dir.value) : null return dirSelect.value ? parseInt(dir.value) : null;
} }
function arrayBufferToBase64(buffer, callback) { function arrayBufferToBase64(buffer, callback) {
const blob = new Blob([buffer], { const blob = new Blob([buffer], {
type: 'application/octet-binary' type: "application/octet-binary",
}) });
const reader = new FileReader() const reader = new FileReader();
reader.onload = function (evt) { reader.onload = function (evt) {
const dataurl = evt.target.result const dataurl = evt.target.result;
callback(dataurl.substr(dataurl.indexOf(',') + 1)) callback(dataurl.substr(dataurl.indexOf(",") + 1));
} };
reader.readAsDataURL(blob) reader.readAsDataURL(blob);
} }
const DirOptions = Object.keys(Dir) const DirOptions = Object.keys(Dir)
.filter((key) => isNaN(parseInt(key))) .filter((key) => isNaN(parseInt(key)))
.map((dir) => [dir, Dir[dir]]) .map((dir) => [dir, Dir[dir]]);
function read() { function read() {
const isFile = pathToRead.match(/\S+\.\S+$/g) const isFile = pathToRead.match(/\S+\.\S+$/g);
const opts = { const opts = {
dir: getDir() dir: getDir(),
} };
const promise = isFile const promise = isFile
? readBinaryFile(pathToRead, opts) ? readBinaryFile(pathToRead, opts)
: readDir(pathToRead, opts) : readDir(pathToRead, opts);
promise promise
.then(function (response) { .then(function (response) {
if (isFile) { if (isFile) {
if (pathToRead.includes('.png') || pathToRead.includes('.jpg')) { if (pathToRead.includes(".png") || pathToRead.includes(".jpg")) {
arrayBufferToBase64(new Uint8Array(response), function (base64) { arrayBufferToBase64(new Uint8Array(response), function (base64) {
const src = 'data:image/png;base64,' + base64 const src = "data:image/png;base64," + base64;
insecureRenderHtml('<img src="' + src + '"></img>') insecureRenderHtml('<img src="' + src + '"></img>');
}) });
} else { } else {
const value = String.fromCharCode.apply(null, response) const value = String.fromCharCode.apply(null, response);
insecureRenderHtml( insecureRenderHtml(
'<textarea id="file-response"></textarea><button id="file-save">Save</button>' '<textarea id="file-response"></textarea><button id="file-save">Save</button>'
) );
setTimeout(() => { setTimeout(() => {
const fileInput = document.getElementById('file-response') const fileInput = document.getElementById("file-response");
fileInput.value = value fileInput.value = value;
document document
.getElementById('file-save') .getElementById("file-save")
.addEventListener('click', function () { .addEventListener("click", function () {
writeTextFile(pathToRead, fileInput.value, { writeTextFile(pathToRead, fileInput.value, {
dir: getDir() dir: getDir(),
}).catch(onMessage) }).catch(onMessage);
}) });
}) });
} }
} else { } else {
onMessage(response) onMessage(response);
} }
}) })
.catch(onMessage) .catch(onMessage);
} }
function setSrc() { function setSrc() {
img.src = convertFileSrc(pathToRead) img.src = convertFileSrc(pathToRead);
} }
</script> </script>

@ -1,60 +1,60 @@
<script> <script>
import { getClient, Body, ResponseType } from 'tauri-plugin-http-api' import { getClient, Body, ResponseType } from "@tauri-apps/plugin-http";
import { JsonView } from '@zerodevx/svelte-json-view' import { JsonView } from "@zerodevx/svelte-json-view";
let httpMethod = 'GET' let httpMethod = "GET";
let httpBody = '' let httpBody = "";
export let onMessage export let onMessage;
async function makeHttpRequest() { async function makeHttpRequest() {
const client = await getClient().catch((e) => { const client = await getClient().catch((e) => {
onMessage(e) onMessage(e);
throw e throw e;
}) });
let method = httpMethod || 'GET' let method = httpMethod || "GET";
const options = { const options = {
url: 'http://localhost:3003', url: "http://localhost:3003",
method: method || 'GET' method: method || "GET",
} };
if ( if (
(httpBody.startsWith('{') && httpBody.endsWith('}')) || (httpBody.startsWith("{") && httpBody.endsWith("}")) ||
(httpBody.startsWith('[') && httpBody.endsWith(']')) (httpBody.startsWith("[") && httpBody.endsWith("]"))
) { ) {
options.body = Body.json(JSON.parse(httpBody)) options.body = Body.json(JSON.parse(httpBody));
} else if (httpBody !== '') { } else if (httpBody !== "") {
options.body = Body.text(httpBody) options.body = Body.text(httpBody);
} }
client.request(options).then(onMessage).catch(onMessage) client.request(options).then(onMessage).catch(onMessage);
} }
/// http form /// http form
let foo = 'baz' let foo = "baz";
let bar = 'qux' let bar = "qux";
let result = null let result = null;
let multipart = true let multipart = true;
async function doPost() { async function doPost() {
const client = await getClient().catch((e) => { const client = await getClient().catch((e) => {
onMessage(e) onMessage(e);
throw e throw e;
}) });
result = await client.request({ result = await client.request({
url: 'http://localhost:3003', url: "http://localhost:3003",
method: 'POST', method: "POST",
body: Body.form({ body: Body.form({
foo, foo,
bar bar,
}), }),
headers: multipart headers: multipart
? { 'Content-Type': 'multipart/form-data' } ? { "Content-Type": "multipart/form-data" }
: undefined, : undefined,
responseType: ResponseType.Text responseType: ResponseType.Text,
}) });
} }
</script> </script>

@ -1,5 +1,5 @@
<script> <script>
import { scan } from "tauri-plugin-barcode-scanner-api"; import { scan } from "@tauri-apps/plugin-barcode-scanner";
export let onMessage; export let onMessage;

@ -1,65 +1,65 @@
<script> <script>
import { Command } from 'tauri-plugin-shell-api' import { Command } from "@tauri-apps/plugin-shell";
const windows = navigator.userAgent.includes('Windows') const windows = navigator.userAgent.includes("Windows");
let cmd = windows ? 'cmd' : 'sh' let cmd = windows ? "cmd" : "sh";
let args = windows ? ['/C'] : ['-c'] let args = windows ? ["/C"] : ["-c"];
export let onMessage export let onMessage;
let script = 'echo "hello world"' let script = 'echo "hello world"';
let cwd = null let cwd = null;
let env = 'SOMETHING=value ANOTHER=2' let env = "SOMETHING=value ANOTHER=2";
let encoding = '' let encoding = "";
let stdin = '' let stdin = "";
let child let child;
function _getEnv() { function _getEnv() {
return env.split(' ').reduce((env, clause) => { return env.split(" ").reduce((env, clause) => {
let [key, value] = clause.split('=') let [key, value] = clause.split("=");
return { return {
...env, ...env,
[key]: value [key]: value,
} };
}, {}) }, {});
} }
function spawn() { function spawn() {
child = null child = null;
const command = Command.create(cmd, [...args, script], { const command = Command.create(cmd, [...args, script], {
cwd: cwd || null, cwd: cwd || null,
env: _getEnv(), env: _getEnv(),
encoding: encoding || undefined, encoding: encoding || undefined,
}) });
command.on('close', (data) => { command.on("close", (data) => {
onMessage( onMessage(
`command finished with code ${data.code} and signal ${data.signal}` `command finished with code ${data.code} and signal ${data.signal}`
) );
child = null child = null;
}) });
command.on('error', (error) => onMessage(`command error: "${error}"`)) command.on("error", (error) => onMessage(`command error: "${error}"`));
command.stdout.on('data', (line) => onMessage(`command stdout: "${line}"`)) command.stdout.on("data", (line) => onMessage(`command stdout: "${line}"`));
command.stderr.on('data', (line) => onMessage(`command stderr: "${line}"`)) command.stderr.on("data", (line) => onMessage(`command stderr: "${line}"`));
command command
.spawn() .spawn()
.then((c) => { .then((c) => {
child = c child = c;
}) })
.catch(onMessage) .catch(onMessage);
} }
function kill() { function kill() {
child child
.kill() .kill()
.then(() => onMessage('killed child process')) .then(() => onMessage("killed child process"))
.catch(onMessage) .catch(onMessage);
} }
function writeToStdin() { function writeToStdin() {
child.write(stdin).catch(onMessage) child.write(stdin).catch(onMessage);
} }
</script> </script>

@ -1,46 +1,46 @@
<script> <script>
import { writable } from 'svelte/store' import { writable } from "svelte/store";
import { import {
register as registerShortcut, register as registerShortcut,
unregister as unregisterShortcut, unregister as unregisterShortcut,
unregisterAll as unregisterAllShortcuts unregisterAll as unregisterAllShortcuts,
} from 'tauri-plugin-global-shortcut-api' } from "@tauri-apps/plugin-global-shortcut";
export let onMessage export let onMessage;
const shortcuts = writable([]) const shortcuts = writable([]);
let shortcut = 'CmdOrControl+X' let shortcut = "CmdOrControl+X";
function register() { function register() {
const shortcut_ = shortcut const shortcut_ = shortcut;
registerShortcut(shortcut_, () => { registerShortcut(shortcut_, () => {
onMessage(`Shortcut ${shortcut_} triggered`) onMessage(`Shortcut ${shortcut_} triggered`);
}) })
.then(() => { .then(() => {
shortcuts.update((shortcuts_) => [...shortcuts_, shortcut_]) shortcuts.update((shortcuts_) => [...shortcuts_, shortcut_]);
onMessage(`Shortcut ${shortcut_} registered successfully`) onMessage(`Shortcut ${shortcut_} registered successfully`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function unregister(shortcut) { function unregister(shortcut) {
const shortcut_ = shortcut const shortcut_ = shortcut;
unregisterShortcut(shortcut_) unregisterShortcut(shortcut_)
.then(() => { .then(() => {
shortcuts.update((shortcuts_) => shortcuts.update((shortcuts_) =>
shortcuts_.filter((s) => s !== shortcut_) shortcuts_.filter((s) => s !== shortcut_)
) );
onMessage(`Shortcut ${shortcut_} unregistered`) onMessage(`Shortcut ${shortcut_} unregistered`);
}) })
.catch(onMessage) .catch(onMessage);
} }
function unregisterAll() { function unregisterAll() {
unregisterAllShortcuts() unregisterAllShortcuts()
.then(() => { .then(() => {
shortcuts.update(() => []) shortcuts.update(() => []);
onMessage(`Unregistered all shortcuts`) onMessage(`Unregistered all shortcuts`);
}) })
.catch(onMessage) .catch(onMessage);
} }
</script> </script>

@ -1,76 +1,86 @@
<script> <script>
import { onMount, onDestroy } from 'svelte' import { check } from "@tauri-apps/plugin-updater";
import { relaunch } from "@tauri-apps/plugin-process";
// This example show how updater events work when dialog is disabled. export let onMessage;
// This allow you to use custom dialog for the updater.
// This is your responsibility to restart the application after you receive the STATUS: DONE.
import { checkUpdate, installUpdate } from '@tauri-apps/api/updater' let isChecking, isInstalling, newUpdate;
import { listen } from '@tauri-apps/api/event' let totalSize = 0,
import { relaunch } from '@tauri-apps/api/process' downloadedSize = 0;
export let onMessage async function checkUpdate() {
let unlisten isChecking = true;
onMount(async () => {
unlisten = await listen('tauri://update-status', onMessage)
})
onDestroy(() => {
if (unlisten) {
unlisten()
}
})
let isChecking, isInstalling, newUpdate
async function check() {
isChecking = true
try { try {
const { shouldUpdate, manifest } = await checkUpdate() const update = await check();
onMessage(`Should update: ${shouldUpdate}`) onMessage(`Should update: ${update.response.available}`);
onMessage(manifest) onMessage(update.response);
newUpdate = shouldUpdate newUpdate = update;
} catch (e) { } catch (e) {
onMessage(e) onMessage(e);
} finally { } finally {
isChecking = false isChecking = false;
} }
} }
async function install() { async function install() {
isInstalling = true isInstalling = true;
downloadedSize = 0;
try { try {
await installUpdate() await newUpdate.downloadAndInstall((downloadProgress) => {
onMessage('Installation complete, restart required.') switch (downloadProgress.event) {
await relaunch() case "Started":
totalSize = downloadProgress.data.contentLength;
break;
case "Progress":
downloadedSize += downloadProgress.data.chunkLength;
break;
case "Finished":
break;
}
});
onMessage("Installation complete, restarting...");
await new Promise((resolve) => setTimeout(resolve, 2000));
await relaunch();
} catch (e) { } catch (e) {
onMessage(e) console.error(e);
onMessage(e);
} finally { } finally {
isInstalling = false isInstalling = false;
} }
} }
$: progress = totalSize ? Math.round((downloadedSize / totalSize) * 100) : 0;
</script> </script>
<div class="flex children:grow children:h10"> <div class="flex children:grow children:h10">
{#if !isChecking && !newUpdate} {#if !isChecking && !newUpdate}
<button class="btn" on:click={check}>Check update</button> <button class="btn" on:click={checkUpdate}>Check update</button>
{:else if !isInstalling && newUpdate} {:else if !isInstalling && newUpdate}
<button class="btn" on:click={install}>Install update</button> <button class="btn" on:click={install}>Install update</button>
{:else} {:else}
<button <div class="progress">
class="btn text-accentText dark:text-darkAccentText flex items-center justify-center" <span>{progress}%</span>
><div class="spinner animate-spin" /></button <div class="progress-bar" style="width: {progress}%" />
> </div>
{/if} {/if}
</div> </div>
<style> <style>
.spinner { .progress {
height: 1.2rem; width: 100%;
width: 1.2rem; height: 50px;
border-radius: 50rem; position: relative;
color: currentColor; margin-top: 5%;
border: 2px dashed currentColor; }
.progress > span {
font-size: 1.2rem;
}
.progress-bar {
height: 30px;
background-color: hsl(32, 94%, 46%);
border: 1px solid #333;
} }
</style> </style>

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save