Resolve merge conflict

pull/1383/head
Noah von Zeppelin 6 months ago
commit 395229e110
No known key found for this signature in database
GPG Key ID: 26F998AF32C08B91

@ -7,5 +7,5 @@ ignore = [
# wry needs kuchiki on Android # wry needs kuchiki on Android
"RUSTSEC-2023-0019", "RUSTSEC-2023-0019",
# atty is only used when the `colored` feature is enabled on tauri-plugin-log # atty is only used when the `colored` feature is enabled on tauri-plugin-log
"RUSTSEC-2021-0145" "RUSTSEC-2021-0145",
] ]

@ -1,5 +0,0 @@
---
"dialog": patch:feat
---
Implement `save` API on Android.

@ -14,10 +14,20 @@
"command": "pnpm build", "command": "pnpm build",
"dryRunCommand": "pnpm build" "dryRunCommand": "pnpm build"
}, },
{
"command": "echo '<details>\n<summary><em><h4>PNPM Publish</h4></em></summary>\n\n```'",
"dryRunCommand": true,
"pipe": true
},
{ {
"command": "npm publish --provenance --access public", "command": "npm publish --provenance --access public",
"dryRunCommand": "npm publish --provenance --access public --dry-run", "dryRunCommand": "npm publish --provenance --access public --dry-run",
"pipe": true "pipe": true
},
{
"command": "echo '```\n\n</details>\n'",
"dryRunCommand": true,
"pipe": true
} }
] ]
}, },
@ -56,12 +66,13 @@
"dependencies": [ "dependencies": [
"barcode-scanner", "barcode-scanner",
"biometric", "biometric",
"log-plugin", "log",
"cli", "cli",
"clipboard-manager", "clipboard-manager",
"dialog", "dialog",
"fs", "fs",
"global-shortcut", "global-shortcut",
"opener",
"http", "http",
"nfc", "nfc",
"notification", "notification",
@ -69,7 +80,9 @@
"process", "process",
"shell", "shell",
"store", "store",
"updater" "updater",
"geolocation",
"haptics"
] ]
}, },
"api-example-js": { "api-example-js": {
@ -85,6 +98,7 @@
"dialog-js", "dialog-js",
"fs-js", "fs-js",
"global-shortcut-js", "global-shortcut-js",
"opener-js",
"http-js", "http-js",
"nfc-js", "nfc-js",
"notification-js", "notification-js",
@ -103,14 +117,6 @@
"dependencies": ["deep-link-js"], "dependencies": ["deep-link-js"],
"postversion": "pnpm install --no-frozen-lockfile" "postversion": "pnpm install --no-frozen-lockfile"
}, },
"authenticator": {
"path": "./plugins/authenticator",
"manager": "rust"
},
"authenticator-js": {
"path": "./plugins/authenticator",
"manager": "javascript"
},
"autostart": { "autostart": {
"path": "./plugins/autostart", "path": "./plugins/autostart",
"manager": "rust" "manager": "rust"
@ -174,7 +180,8 @@
}, },
"dialog-js": { "dialog-js": {
"path": "./plugins/dialog", "path": "./plugins/dialog",
"manager": "javascript" "manager": "javascript",
"dependencies": ["fs-js"]
}, },
"geolocation": { "geolocation": {
"path": "./plugins/geolocation", "path": "./plugins/geolocation",
@ -192,6 +199,14 @@
"path": "./plugins/global-shortcut", "path": "./plugins/global-shortcut",
"manager": "javascript" "manager": "javascript"
}, },
"opener": {
"path": "./plugins/opener",
"manager": "rust"
},
"opener-js": {
"path": "./plugins/opener",
"manager": "javascript"
},
"haptics": { "haptics": {
"path": "./plugins/haptics", "path": "./plugins/haptics",
"manager": "rust" "manager": "rust"
@ -207,13 +222,14 @@
}, },
"http-js": { "http-js": {
"path": "./plugins/http", "path": "./plugins/http",
"manager": "javascript" "manager": "javascript",
"dependencies": ["fs-js"]
}, },
"localhost": { "localhost": {
"path": "./plugins/localhost", "path": "./plugins/localhost",
"manager": "rust" "manager": "rust"
}, },
"log-plugin": { "log": {
"path": "./plugins/log", "path": "./plugins/log",
"manager": "rust" "manager": "rust"
}, },
@ -276,7 +292,8 @@
}, },
"single-instance": { "single-instance": {
"path": "./plugins/single-instance", "path": "./plugins/single-instance",
"manager": "rust" "manager": "rust",
"dependencies": ["deep-link"]
}, },
"sql": { "sql": {
"path": "./plugins/sql", "path": "./plugins/sql",

@ -1,5 +0,0 @@
---
"dialog": "patch"
---
Mark `FileResponse` as `non_exhaustive`.

@ -1,7 +0,0 @@
---
"dialog": patch
"dialog-js": patch
---
The `open` function now returns a string representing either the file path or URI instead of an object.
To read the file data, use the `fs` APIs.

@ -1,5 +0,0 @@
---
"http-js": patch
---
Fixed an issue with abort signal not aborting the fetch request.

@ -1,5 +0,0 @@
---
"updater": patch
---
Fixes the updater not preserving AppImage file permissions.

@ -1,5 +0,0 @@
---
"fs": patch:enhance
---
The `scope-*-recursive` permissions now also allow reading the contents of the directory.

@ -1,6 +0,0 @@
---
"geolocation": major
"geolocation-js": major
---
Initial release.

@ -1,5 +0,0 @@
---
"global-shortcut": "patch"
---
Updated `global-hotkey` crate dependency to `0.6`

@ -1,6 +0,0 @@
---
"haptics": major
"haptics-js": major
---
Initial release.

@ -1,9 +0,0 @@
---
barcode-scanner: patch
clipboard-manager: patch
deep-link: patch
global-shortcut: patch
window-state: patch
---
Fixed an issue that caused multi-word IIFE names to not be formatted correctly. For example the `barcode-scanner` was defined as `window.__TAURI_PLUGIN_CLIPBOARDMANAGER__` instead of `window.__TAURI_PLUGIN_CLIPBOARD_MANAGER__`.

@ -1,18 +0,0 @@
{
"tag": "rc",
"changes": [
".changes/android-dialog-save.md",
".changes/fix-http-plugin-abort.md",
".changes/fix-linux-updater-permission-error.md",
".changes/geolocation-release.md",
".changes/haptics-release.md",
".changes/iife-varname-spacing.md",
".changes/rc.md",
".changes/remove-target-sdk.md",
".changes/shell-open-regex-match-string.md",
".changes/shell-regex-match-string.md",
".changes/swift-build-older-versions.md",
".changes/update-fs-api-docs.md",
".changes/update-tauri-rc-3.md"
]
}

@ -1,61 +0,0 @@
---
"authenticator": patch
"autostart": patch
"barcode-scanner": patch
"biometric": patch
"cli": patch
"clipboard-manager": patch
"deep-link": patch
"dialog": patch
"fs": patch
"global-shortcut": patch
"http": patch
"localhost": patch
"log-plugin": patch
"nfc": patch
"notification": patch
"os": patch
"persisted-scope": patch
"positioner": patch
"process": patch
"shell": patch
"single-instance": patch
"sql": patch
"store": patch
"stronghold": patch
"updater": patch
"upload": patch
"websocket": patch
"window-state": patch
"authenticator-js": patch
"autostart-js": patch
"barcode-scanner-js": patch
"biometric-js": patch
"cli-js": patch
"clipboard-manager-js": patch
"deep-link-js": patch
"dialog-js": patch
"fs-js": patch
"global-shortcut-js": patch
"http-js": patch
"log-js": patch
"nfc-js": patch
"notification-js": patch
"os-js": patch
"positioner-js": patch
"process-js": patch
"shell-js": patch
"sql-js": patch
"store-js": patch
"stronghold-js": patch
"updater-js": patch
"upload-js": patch
"websocket-js": patch
"window-state-js": patch
"haptics": patch
"haptics-js": patch
"geolocation": patch
"geolocation-js": patch
---
Update to tauri RC.

@ -6,6 +6,8 @@ As you create PRs and make changes that require a version bump, please add a new
When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process. When you select the version bump required, you do _not_ need to consider dependencies. Only note the package with the actual change, and any packages that depend on that package will be bumped automatically in the process.
**Note, that in this repository, even if only the Rust code or only the JavaScript code of a plugin changed, both packages need to be bumped with the same increment!**
Use the following format: Use the following format:
```md ```md

@ -1,15 +0,0 @@
---
"barcode-scanner": patch:changes
"biometric": patch:changes
"clipboard-manager": patch:changes
"deep-link": patch:changes
"dialog": patch:changes
"geolocation": patch:changes
"haptics": patch:changes
"nfc": patch:changes
"notification": patch:changes
"shell": patch:changes
"store": patch:changes
---
Remove targetSdk from build.kts files as it is deprecated and will be removed from DSL v9.0

@ -1,5 +0,0 @@
---
"fs": patch:feat
---
Resolve `content://` path URIs on Android.

@ -1,5 +0,0 @@
---
"shell": patch
---
Change the `open` scope validator regex to match on the entire string.

@ -1,6 +0,0 @@
---
"shell": patch
---
Change the `execute` scope argument validator regex to match on the entire string by default.
If this behavior is not desired check the `raw` boolean configuration option that is available along the `validator` string.

@ -1,5 +0,0 @@
---
"single-instance": "patch"
---
Updated `windows-sys` crate to `0.59`

@ -1,5 +0,0 @@
---
"store": patch:breaking
---
Implement mobile support in Rust directly. This changes the store directories, invalidating all previously generated stores.

@ -1,15 +0,0 @@
---
"barcode-scanner": patch
"biometric": patch
"clipboard-manager": patch
"dialog": patch
"geolocation": patch
"haptics": patch
"log-plugin": patch
"nfc": patch
"notification": patch
"shell": patch
"store": patch
---
Explicitly set a minimum macOS version for the Swift package.

@ -1,5 +0,0 @@
---
"fs-js": patch
---
Update documentation.

@ -1,7 +0,0 @@
---
"geolocation": patch
"deep-link": patch
"updater": patch
---
Update to tauri 2.0.0-rc.3.

@ -7,23 +7,23 @@ name: Audit JavaScript
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: "0 0 * * *" - cron: '0 0 * * *'
push: push:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/audit-javascript.yml" - '.github/workflows/audit-javascript.yml'
- "**/pnpm-lock.yaml" - '**/pnpm-lock.yaml'
- "**/package.json" - '**/package.json'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/audit-javascript.yml" - '.github/workflows/audit-javascript.yml'
- "**/pnpm-lock.yaml" - '**/pnpm-lock.yaml'
- "**/package.json" - '**/package.json'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -43,7 +43,7 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "lts/*" node-version: 'lts/*'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:
version: 9.x.x version: 9.x.x

@ -7,23 +7,23 @@ name: Audit Rust
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
- cron: "0 0 * * *" - cron: '0 0 * * *'
push: push:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/audit-rust.yml" - '.github/workflows/audit-rust.yml'
- "**/Cargo.lock" - '**/Cargo.lock'
- "**/Cargo.toml" - '**/Cargo.toml'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/audit-rust.yml" - '.github/workflows/audit-rust.yml'
- "**/Cargo.lock" - '**/Cargo.lock'
- "**/Cargo.toml" - '**/Cargo.toml'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}

@ -0,0 +1,44 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check change files
on:
pull_request:
paths:
- '.changes/*.md'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: check change files end with .md
run: |
for file in .changes/*
do
if [[ ! "$file" =~ \.(md|json)$ ]]; then
echo ".changes directory should only contain files that end with .md"
echo "found an invalid file in .changes directory:"
echo "$file"
exit 1
fi
done
- uses: dorny/paths-filter@v3
id: filter
with:
list-files: shell
filters: |
changes:
- added|modified: '.changes/*.md'
- name: check
run: node ./.scripts/ci/check-change-files.js ${{ steps.filter.outputs.changes_files }}
if: ${{ steps.filter.outputs.changes == 'true' }}

@ -7,8 +7,8 @@ name: check generated files
on: on:
pull_request: pull_request:
paths: paths:
- ".github/workflows/check-generated-files.yml" - '.github/workflows/check-generated-files.yml'
- "**/guest-js/**" - '**/guest-js/**'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -25,10 +25,6 @@ jobs:
id: filter id: filter
with: with:
filters: | filters: |
authenticator:
- .github/workflows/check-generated-files.yml
- plugins/authenticator/guest-js/**
- plugins/authenticator/src/api-iife.js
autostart: autostart:
- .github/workflows/check-generated-files.yml - .github/workflows/check-generated-files.yml
- plugins/autostart/guest-js/** - plugins/autostart/guest-js/**
@ -57,6 +53,10 @@ jobs:
- .github/workflows/check-generated-files.yml - .github/workflows/check-generated-files.yml
- plugins/global-shortcut/guest-js/** - plugins/global-shortcut/guest-js/**
- plugins/global-shortcut/src/api-iife.js - plugins/global-shortcut/src/api-iife.js
opener:
- .github/workflows/check-generated-files.yml
- plugins/opener/guest-js/**
- plugins/opener/src/api-iife.js
haptics: haptics:
- .github/workflows/check-generated-files.yml - .github/workflows/check-generated-files.yml
- plugins/haptics/guest-js/** - plugins/haptics/guest-js/**
@ -140,7 +140,7 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "lts/*" node-version: 'lts/*'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:
version: 9.x.x version: 9.x.x

@ -27,4 +27,4 @@ jobs:
uses: jbolda/covector/packages/action@covector-v0 uses: jbolda/covector/packages/action@covector-v0
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
command: "status" command: 'status'

@ -17,6 +17,6 @@ jobs:
uses: jbolda/covector/packages/action@covector-v0 uses: jbolda/covector/packages/action@covector-v0
id: covector id: covector
with: with:
command: "status" command: 'status'
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
comment: true comment: true

@ -34,8 +34,8 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "lts/*" node-version: 'lts/*'
registry-url: "https://registry.npmjs.org" registry-url: 'https://registry.npmjs.org'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:
@ -65,7 +65,7 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }} NODE_AUTH_TOKEN: ${{ secrets.ORG_NPM_TOKEN }}
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
command: "version-or-publish" command: 'version-or-publish'
createRelease: true createRelease: true
recognizeContributors: true recognizeContributors: true
@ -78,8 +78,8 @@ jobs:
uses: tauri-apps/create-pull-request@v3 uses: tauri-apps/create-pull-request@v3
if: steps.covector.outputs.commandRan == 'version' if: steps.covector.outputs.commandRan == 'version'
with: with:
title: "Publish New Versions (${{ github.ref_name }})" title: 'Publish New Versions (${{ github.ref_name }})'
commit-message: "publish new versions" commit-message: 'publish new versions'
labels: "version updates" labels: 'version updates'
branch: "ci/release-${{ github.ref_name }}" branch: 'ci/release-${{ github.ref_name }}'
body: ${{ steps.covector.outputs.change }} body: ${{ steps.covector.outputs.change }}

@ -0,0 +1,59 @@
# Copyright 2019-2023 Tauri Programme within The Commons Conservancy
# SPDX-License-Identifier: Apache-2.0
# SPDX-License-Identifier: MIT
name: check formatting
on:
pull_request:
jobs:
rustfmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install Rust stable and rustfmt
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt
- name: run cargo fmt
run: cargo fmt --all -- --check
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache pnpm modules
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- uses: actions/setup-node@v4
with:
node-version: 'lts/*'
- uses: pnpm/action-setup@v4
with:
version: 9.x.x
run_install: true
- run: pnpm format:check
taplo:
name: taplo (.toml files)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: install Rust stable
uses: dtolnay/rust-toolchain@stable
- name: install taplo-cli
uses: taiki-e/install-action@v2
with:
tool: taplo-cli
- run: taplo fmt --check --diff

@ -10,15 +10,15 @@ on:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/integration-tests.yml" - '.github/workflows/integration-tests.yml'
- "plugins/updater/src/**" - 'plugins/updater/src/**'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/integration-tests.yml" - '.github/workflows/integration-tests.yml'
- "plugins/updater/src/**" - 'plugins/updater/src/**'
jobs: jobs:
run-integration-tests: run-integration-tests:

@ -10,23 +10,23 @@ on:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/lint-javascript.yml" - '.github/workflows/lint-javascript.yml'
- "plugins/*/guest-js/**" - 'plugins/*/guest-js/**'
- ".eslintignore" - '.eslintignore'
- ".eslintrc.json" - '.eslintrc.json'
- ".prettierignore" - '.prettierignore'
- "**/package.json" - '**/package.json'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/lint-javascript.yml" - '.github/workflows/lint-javascript.yml'
- "plugins/*/guest-js/**" - 'plugins/*/guest-js/**'
- ".eslintignore" - '.eslintignore'
- ".eslintrc.json" - '.eslintrc.json'
- ".prettierignore" - '.prettierignore'
- "**/package.json" - '**/package.json'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -46,30 +46,10 @@ jobs:
${{ runner.os }}- ${{ runner.os }}-
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "lts/*" node-version: 'lts/*'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:
version: 9.x.x version: 9.x.x
run_install: true run_install: true
- name: eslint - name: eslint
run: pnpm lint run: pnpm lint
prettier:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Cache pnpm modules
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: ${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-
- uses: actions/setup-node@v4
with:
node-version: "lts/*"
- uses: pnpm/action-setup@v4
with:
version: 9.x.x
run_install: true
- name: prettier check
run: pnpm format-check

@ -10,19 +10,19 @@ on:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/lint-rust.yml" - '.github/workflows/lint-rust.yml'
- "plugins/*/src/**" - 'plugins/*/src/**'
- "!plugins/*/src/api-iife.js" - '!plugins/*/src/api-iife.js'
- "**/Cargo.toml" - '**/Cargo.toml'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/lint-rust.yml" - '.github/workflows/lint-rust.yml'
- "plugins/*/src/**" - 'plugins/*/src/**'
- "!plugins/*/src/api-iife.js" - '!plugins/*/src/api-iife.js'
- "**/Cargo.toml" - '**/Cargo.toml'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -41,9 +41,6 @@ jobs:
id: filter id: filter
with: with:
filters: | filters: |
tauri-plugin-authenticator:
- .github/workflows/lint-rust.yml
- plugins/authenticator/**
tauri-plugin-autostart: tauri-plugin-autostart:
- .github/workflows/lint-rust.yml - .github/workflows/lint-rust.yml
- plugins/autostart/** - plugins/autostart/**
@ -69,6 +66,9 @@ jobs:
tauri-plugin-global-shortcut: tauri-plugin-global-shortcut:
- .github/workflows/lint-rust.yml - .github/workflows/lint-rust.yml
- plugins/global-shortcut/** - plugins/global-shortcut/**
tauri-plugin-opener:
- .github/workflows/lint-rust.yml
- plugins/opener/**
tauri-plugin-haptics: tauri-plugin-haptics:
- .github/workflows/lint-rust.yml - .github/workflows/lint-rust.yml
- plugins/haptics/** - plugins/haptics/**
@ -129,7 +129,7 @@ jobs:
clippy: clippy:
needs: changes needs: changes
if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }} if: ${{ needs.changes.outputs.packages != '[]' && needs.changes.outputs.packages != '' }}
runs-on: ubuntu-latest runs-on: ubuntu-22.04
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
@ -138,10 +138,10 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: install webkit2gtk and libudev for [authenticator] - name: install webkit2gtk
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev
- name: Install clippy with stable toolchain - name: Install clippy with stable toolchain
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable
@ -150,32 +150,8 @@ jobs:
- uses: Swatinem/rust-cache@v2 - uses: Swatinem/rust-cache@v2
- name: create dummy dist
working-directory: examples/api
run: mkdir dist
- name: clippy ${{ matrix.package }} - name: clippy ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings run: cargo clippy --package ${{ matrix.package }} --all-targets -- -D warnings
- name: clippy ${{ matrix.package }} mysql - name: clippy ${{ matrix.package }} --all-features
if: matrix.package == 'tauri-plugin-sql' run: cargo clippy --package ${{ matrix.package }} --all-targets --all-features -- -D warnings
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features mysql -- -D warnings
- name: clippy ${{ matrix.package }} postgres
if: matrix.package == 'tauri-plugin-sql'
run: cargo clippy --package ${{ matrix.package }} --all-targets --no-default-features --features postgres -- -D warnings
fmt:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install rustfmt with nightly toolchain
uses: dtolnay/rust-toolchain@nightly
with:
components: rustfmt
- name: Check formatting
run: cargo fmt --all -- --check

@ -34,7 +34,7 @@ jobs:
- uses: actions/setup-node@v4 - uses: actions/setup-node@v4
with: with:
node-version: "lts/*" node-version: 'lts/*'
- uses: pnpm/action-setup@v4 - uses: pnpm/action-setup@v4
with: with:

@ -10,21 +10,21 @@ on:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/test-rust.yml" - '.github/workflows/test-rust.yml'
- "plugins/*/src/**" - 'plugins/*/src/**'
- "!plugins/*/src/api-iife.js" - '!plugins/*/src/api-iife.js'
- "**/Cargo.toml" - '**/Cargo.toml'
- "**/Cargo.lock" - '**/Cargo.lock'
pull_request: pull_request:
branches: branches:
- v1 - v1
- v2 - v2
paths: paths:
- ".github/workflows/test-rust.yml" - '.github/workflows/test-rust.yml'
- "plugins/*/src/**" - 'plugins/*/src/**'
- "!plugins/*/src/api-iife.js" - '!plugins/*/src/api-iife.js'
- "**/Cargo.toml" - '**/Cargo.toml'
- "**/Cargo.lock" - '**/Cargo.lock'
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -44,116 +44,143 @@ jobs:
with: with:
base: v2 base: v2
filters: | filters: |
tauri-plugin-authenticator:
- .github/workflows/test-rust.yml
- Cargo.toml
- plugins/authenticator/**
tauri-plugin-autostart: tauri-plugin-autostart:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/autostart/** - plugins/autostart/**
tauri-plugin-cli: tauri-plugin-cli:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/cli/** - plugins/cli/**
tauri-plugin-clipboard-manager: tauri-plugin-clipboard-manager:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/clipboard-manager/** - plugins/clipboard-manager/**
tauri-plugin-deep-link: tauri-plugin-deep-link:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/deep-link/** - plugins/deep-link/**
tauri-plugin-dialog: tauri-plugin-dialog:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/dialog/** - plugins/dialog/**
- plugins/fs/** - plugins/fs/**
tauri-plugin-fs: tauri-plugin-fs:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/fs/** - plugins/fs/**
tauri-plugin-geolocation: tauri-plugin-geolocation:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/geolocation/** - plugins/geolocation/**
tauri-plugin-global-shortcut: tauri-plugin-global-shortcut:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/global-shortcut/** - plugins/global-shortcut/**
tauri-plugin-opener:
- .github/workflows/test-rust.yml
- Cargo.toml
- Cargo.lock
- plugins/opener/**
tauri-plugin-haptics: tauri-plugin-haptics:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/haptics/** - plugins/haptics/**
tauri-plugin-http: tauri-plugin-http:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/http/** - plugins/http/**
- plugins/fs/** - plugins/fs/**
tauri-plugin-localhost: tauri-plugin-localhost:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/localhost/** - plugins/localhost/**
tauri-plugin-log: tauri-plugin-log:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/log/** - plugins/log/**
tauri-plugin-notification: tauri-plugin-notification:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/notification/** - plugins/notification/**
tauri-plugin-os: tauri-plugin-os:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/os/** - plugins/os/**
tauri-plugin-persisted-scope: tauri-plugin-persisted-scope:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/persisted-scope/** - plugins/persisted-scope/**
- plugins/fs/** - plugins/fs/**
tauri-plugin-positioner: tauri-plugin-positioner:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/positioner/** - plugins/positioner/**
tauri-plugin-process: tauri-plugin-process:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/process/** - plugins/process/**
tauri-plugin-shell: tauri-plugin-shell:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/shell/** - plugins/shell/**
tauri-plugin-single-instance: tauri-plugin-single-instance:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/single-instance/** - plugins/single-instance/**
tauri-plugin-sql: tauri-plugin-sql:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/sql/** - plugins/sql/**
tauri-plugin-store: tauri-plugin-store:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/store/** - plugins/store/**
tauri-plugin-stronghold: tauri-plugin-stronghold:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/stronghold/** - plugins/stronghold/**
tauri-plugin-updater: tauri-plugin-updater:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/updater/** - plugins/updater/**
tauri-plugin-upload: tauri-plugin-upload:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/upload/** - plugins/upload/**
tauri-plugin-websocket: tauri-plugin-websocket:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/websocket/** - plugins/websocket/**
tauri-plugin-window-state: tauri-plugin-window-state:
- .github/workflows/test-rust.yml - .github/workflows/test-rust.yml
- Cargo.toml - Cargo.toml
- Cargo.lock
- plugins/window-state/** - plugins/window-state/**
test: test:
@ -167,32 +194,32 @@ jobs:
- { - {
target: x86_64-pc-windows-msvc, target: x86_64-pc-windows-msvc,
os: windows-latest, os: windows-latest,
runner: "cargo", runner: 'cargo',
command: "test", command: 'test'
} }
- { - {
target: x86_64-unknown-linux-gnu, target: x86_64-unknown-linux-gnu,
os: ubuntu-latest, os: ubuntu-22.04,
runner: "cargo", runner: 'cargo',
command: "test", command: 'test'
} }
- { - {
target: aarch64-apple-darwin, target: aarch64-apple-darwin,
os: macos-latest, os: macos-latest,
runner: "cargo", runner: 'cargo',
command: "test", command: 'test'
} }
- { - {
target: aarch64-apple-ios, target: aarch64-apple-ios,
os: macos-latest, os: macos-latest,
runner: "cargo", runner: 'cargo',
command: "build", command: 'build'
} }
- { - {
target: aarch64-linux-android, target: aarch64-linux-android,
os: ubuntu-latest, os: ubuntu-latest,
runner: "cross", runner: 'cross',
command: "build", command: 'build'
} }
runs-on: ${{ matrix.platform.os }} runs-on: ${{ matrix.platform.os }}
@ -200,19 +227,13 @@ jobs:
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
- name: install webkit2gtk and libudev for [authenticator] - name: install webkit2gtk
if: contains(matrix.platform.target, 'unknown-linux') if: contains(matrix.platform.target, 'unknown-linux')
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev
- name: install openssl - uses: dtolnay/rust-toolchain@1.77.2
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.75.0
with: with:
targets: ${{ matrix.platform.target }} targets: ${{ matrix.platform.target }}
@ -220,30 +241,14 @@ jobs:
with: with:
key: cache-${{ matrix.package }}-${{ matrix.platform.target }} key: cache-${{ matrix.package }}-${{ matrix.platform.target }}
- name: create dummy dist
working-directory: examples/api
run: mkdir dist
- name: install cross - name: install cross
if: ${{ matrix.platform.runner == 'cross' }} if: ${{ matrix.platform.runner == 'cross' }}
run: cargo +stable install cross --git https://github.com/cross-rs/cross run: cargo +stable install cross --git https://github.com/cross-rs/cross
- name: test ${{ matrix.package }} - name: test ${{ matrix.package }}
if: matrix.package != 'tauri-plugin-sql' && matrix.package != 'tauri-plugin-http' if: matrix.package != 'tauri-plugin-http'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --all-features
- name: test ${{ matrix.package }} - name: test ${{ matrix.package }}
if: matrix.package == 'tauri-plugin-http' if: matrix.package == 'tauri-plugin-http'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets
- name: test ${{ matrix.package }} sqlite
if: matrix.package == 'tauri-plugin-sql'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features sqlite
- name: test ${{ matrix.package }} mysql
if: matrix.package == 'tauri-plugin-sql'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features mysql
- name: test ${{ matrix.package }} postgres
if: matrix.package == 'tauri-plugin-sql'
run: ${{ matrix.platform.runner }} ${{ matrix.platform.command }} --package ${{ matrix.package }} --target ${{ matrix.platform.target }} --all-targets --features postgres

64
.gitignore vendored

@ -1,8 +1,58 @@
target # dependency directories
node_modules node_modules/
dist-js target/
dist
# Optional npm and yarn cache directory
.npm/
.yarn/
# Output of 'npm pack'
*.tgz
# dotenv environment variables file
.env
# .vscode workspace settings file
.vscode/settings.json
# npm, yarn and bun lock files
package-lock.json
yarn.lock
bun.lockb
# rust compiled folders
target/
# compiled plugins
dist-js/
# plugins .tauri directory
/plugins/*/.tauri
# examples
examples/*/dist
plugins/*/examples/*/dist
examples/*/src-tauri/gen/schemas
plugins/*/examples/*/src-tauri/gen/schemas
# logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# runtime data
pids
*.pid
*.seed
*.pid.lock
# miscellaneous
/.vs
.DS_Store
.Thumbs.db
*.sublime*
.idea .idea
.vscode debug.log
.gradle TODO.md
**/capabilities/schemas

@ -1,12 +1,27 @@
target /.changes
node_modules /.vscode
dist
dist-js # dependcies and artifacts directories
node_modules/
target/
dist-js/
dist/
# lock files
pnpm-lock.yaml pnpm-lock.yaml
Cargo.lock
.build # examples gen directory
build examples/*/src-tauri/gen/
plugins/*/examples/*/src-tauri/gen/
# autogenerated files
**/autogenerated/**/*.md
api-iife.js api-iife.js
init-iife.js init-iife.js
intermediates/ CHANGELOG.md
*schema.json *schema.json
# mobile build
**/ios/.build
**/.tauri
plugins/*/android/build

@ -0,0 +1,5 @@
{
"singleQuote": true,
"semi": false,
"trailingComma": "none"
}

@ -0,0 +1,86 @@
#!/usr/bin/env node
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import { readFileSync, readdirSync } from 'fs'
import { join } from 'path'
/* const ignorePackages = [
'api-example',
'api-example-js',
'deep-link-example',
'deep-link-example-js'
] */
const rsOnly = ['localhost', 'persisted-scope', 'single-instance']
function checkChangeFiles(changeFiles) {
let code = 0
for (const file of changeFiles) {
const content = readFileSync(file, 'utf8')
const [frontMatter] = /^---[\s\S.]*---\n/i.exec(content)
const packages = frontMatter
.split('\n')
.filter((l) => !(l === '---' || !l))
.map((l) => l.replace(/('|")/g, '').split(':'))
const rsPackages = Object.fromEntries(
packages
.filter((v) => !v[0].endsWith('-js'))
.map((v) => [v[0], v[1].trim()])
)
const jsPackages = Object.fromEntries(
packages
.filter((v) => v[0].endsWith('-js'))
.map((v) => [v[0].slice(0, -3), v[1].trim()])
)
for (const pkg in rsPackages) {
if (rsOnly.includes(pkg)) continue
if (!jsPackages[pkg]) {
console.error(
`Missing "${rsPackages[pkg]}" bump for JS package "${pkg}-js" in ${file}.`
)
code = 1
} else if (rsPackages[pkg] != jsPackages[pkg]) {
console.error(
`"${pkg}" and "${pkg}-js" have different version bumps in ${file}.`
)
code = 1
}
}
for (const pkg in jsPackages) {
if (!rsPackages[pkg]) {
console.error(
`Missing "${jsPackages[pkg]}" bump for Rust package "${pkg}" in ${file}.`
)
code = 1
} else if (rsPackages[pkg] != jsPackages[pkg]) {
console.error(
`"${pkg}" and "${pkg}-js" have different version bumps in ${file}.`
)
code = 1
}
}
}
process.exit(code)
}
const [_bin, _script, ...files] = process.argv
if (files.length > 0) {
checkChangeFiles(
files.filter((f) => f.toLowerCase() !== '.changes/readme.md')
)
} else {
const changeFiles = readdirSync('.changes')
.filter((f) => f.endsWith('.md') && f.toLowerCase() !== 'readme.md')
.map((p) => join('.changes', p))
checkChangeFiles(changeFiles)
}

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

@ -0,0 +1 @@
plugins/*/permissions/autogenerated/

@ -0,0 +1,8 @@
{
"recommendations": [
"rust-lang.rust-analyzer",
"EditorConfig.EditorConfig",
"esbenp.prettier-vscode",
"tamasfe.even-better-toml"
]
}

2827
Cargo.lock generated

File diff suppressed because it is too large Load Diff

@ -10,24 +10,31 @@ resolver = "2"
[workspace.dependencies] [workspace.dependencies]
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
tracing = "0.1"
log = "0.4" log = "0.4"
tauri = { version = "2.0.0-rc.5", default-features = false } tauri = { version = "2", default-features = false }
tauri-build = "2.0.0-rc.5" tauri-build = "2"
tauri-plugin = "2.0.0-rc.5" tauri-plugin = "2"
tauri-utils = "2.0.0-rc.5" tauri-utils = "2"
serde_json = "1" serde_json = "1"
thiserror = "1" thiserror = "2"
url = "2" url = "2"
schemars = "0.8" schemars = "0.8"
dunce = "1" dunce = "1"
specta = "=2.0.0-rc.20" specta = "=2.0.0-rc.20"
# TODO: remove when specta releases rc.21
specta-util = { version = "^0.0.7", default-features = false, features = [
"export",
] }
glob = "0.3"
zbus = "4"
#tauri-specta = "=2.0.0-rc.11" #tauri-specta = "=2.0.0-rc.11"
[workspace.package] [workspace.package]
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.75" rust-version = "1.77.2"
repository = "https://github.com/tauri-apps/plugins-workspace" repository = "https://github.com/tauri-apps/plugins-workspace"
# default to small, optimized release binaries # default to small, optimized release binaries

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

@ -20,4 +20,4 @@ We prefer to receive reports in English.
Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new). Please disclose a vulnerability or security relevant issue here: [https://github.com/tauri-apps/plugins-workspace/security/advisories/new](https://github.com/tauri-apps/plugins-workspace/security/advisories/new).
Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app). Alternatively, you can also contact us by email via [security@tauri.app](mailto:security@tauri.app).

@ -2,28 +2,29 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import eslint from "@eslint/js"; import eslint from '@eslint/js'
import eslintConfigPrettier from "eslint-config-prettier"; import eslintConfigPrettier from 'eslint-config-prettier'
import eslintPluginSecurity from "eslint-plugin-security"; import eslintPluginSecurity from 'eslint-plugin-security'
import tseslint from "typescript-eslint"; import tseslint from 'typescript-eslint'
export default tseslint.config( export default tseslint.config(
{ {
ignores: [ ignores: [
"**/target", '**/target',
"**/node_modules", '**/node_modules',
"**/examples", '**/examples',
"**/dist", '**/dist',
"**/dist-js", '**/dist-js',
"**/build", '**/build',
"**/api-iife.js", '**/api-iife.js',
"**/init-iife.js", '**/init-iife.js',
"**/init.js", '**/init.js',
"**/rollup.config.js", '**/rollup.config.js',
"**/bindings.ts", '**/bindings.ts',
".scripts", '**/.test-server',
"eslint.config.js", '.scripts',
], 'eslint.config.js'
]
}, },
eslint.configs.recommended, eslint.configs.recommended,
eslintConfigPrettier, eslintConfigPrettier,
@ -31,7 +32,7 @@ export default tseslint.config(
...tseslint.configs.recommendedTypeChecked, ...tseslint.configs.recommendedTypeChecked,
{ {
languageOptions: { languageOptions: {
parserOptions: { project: true, tsconfigRootDir: import.meta.dirname }, parserOptions: { project: true, tsconfigRootDir: import.meta.dirname }
}, }
}, }
); )

@ -1,4 +0,0 @@
/node_modules/
/.vscode/
.DS_Store
.cargo

@ -1,5 +1,149 @@
# Changelog # Changelog
## \[2.0.9]
### Dependencies
- Upgraded to `opener-js@2.2.3`
- Upgraded to `updater-js@2.3.1`
## \[2.0.8]
### Dependencies
- Upgraded to `opener-js@2.2.2`
## \[2.0.7]
### Dependencies
- Upgraded to `updater-js@2.3.0`
- Upgraded to `opener-js@2.2.1`
## \[2.0.6]
### Dependencies
- Upgraded to `barcode-scanner-js@2.1.0`
- Upgraded to `biometric-js@2.1.0`
- Upgraded to `cli-js@2.1.0`
- Upgraded to `clipboard-manager-js@2.1.0`
- Upgraded to `dialog-js@2.1.0`
- Upgraded to `fs-js@2.1.0`
- Upgraded to `global-shortcut-js@2.1.0`
- Upgraded to `http-js@2.1.0`
- Upgraded to `log-js@2.1.0`
- Upgraded to `nfc-js@2.1.0`
- Upgraded to `notification-js@2.1.0`
- Upgraded to `opener-js@2.1.0`
- Upgraded to `os-js@2.1.0`
- Upgraded to `process-js@2.1.0`
- Upgraded to `shell-js@2.1.0`
- Upgraded to `store-js@2.2.0`
- Upgraded to `updater-js@2.1.0`
## \[2.0.5]
### Dependencies
- Upgraded to `fs-js@2.0.4`
- Upgraded to `dialog-js@2.0.2`
- Upgraded to `http-js@2.0.2`
## \[2.0.4]
### Dependencies
- Upgraded to `log-js@2.0.2`
## \[2.0.3]
### Dependencies
- Upgraded to `clipboard-manager-js@2.0.1`
- Upgraded to `log-js@2.0.1`
- Upgraded to `fs-js@2.0.3`
- Upgraded to `opener-js@2.0.0`
## \[2.0.2]
### Dependencies
- Upgraded to `fs-js@2.0.2`
## \[2.0.1]
### Dependencies
- Upgraded to `dialog-js@2.0.1`
- Upgraded to `fs-js@2.0.1`
- Upgraded to `http-js@2.0.1`
- Upgraded to `shell-js@2.0.1`
- Upgraded to `store-js@2.1.0`
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
### Dependencies
- Upgraded to `barcode-scanner-js@2.0.0`
- Upgraded to `biometric-js@2.0.0`
- Upgraded to `cli-js@2.0.0`
- Upgraded to `clipboard-manager-js@2.0.0`
- Upgraded to `fs-js@2.0.0`
- Upgraded to `dialog-js@2.0.0`
- Upgraded to `global-shortcut-js@2.0.0`
- Upgraded to `http-js@2.0.0`
- Upgraded to `log-js@2.0.0`
- Upgraded to `nfc-js@2.0.0`
- Upgraded to `notification-js@2.0.0`
- Upgraded to `os-js@2.0.0`
- Upgraded to `process-js@2.0.0`
- Upgraded to `shell-js@2.0.0`
- Upgraded to `store-js@2.0.0`
- Upgraded to `updater-js@2.0.0`
## \[2.0.0-rc.5]
### Dependencies
- Upgraded to `store-js@2.0.0-rc.2`
## \[2.0.0-rc.4]
### Dependencies
- Upgraded to `barcode-scanner-js@2.0.0-rc.2`
- Upgraded to `clipboard-manager-js@2.0.0-rc.2`
## \[2.0.0-rc.3]
### Dependencies
- Upgraded to `updater-js@2.0.0-rc.2`
## \[2.0.0-rc.2]
### Dependencies
- Upgraded to `barcode-scanner-js@2.0.0-rc.1`
- Upgraded to `notification-js@2.0.0-rc.1`
- Upgraded to `dialog-js@2.0.0-rc.1`
- Upgraded to `biometric-js@2.0.0-rc.1`
- Upgraded to `cli-js@2.0.0-rc.1`
- Upgraded to `clipboard-manager-js@2.0.0-rc.1`
- Upgraded to `fs-js@2.0.0-rc.2`
- Upgraded to `global-shortcut-js@2.0.0-rc.1`
- Upgraded to `http-js@2.0.0-rc.2`
- Upgraded to `log-js@2.0.0-rc.1`
- Upgraded to `nfc-js@2.0.0-rc.1`
- Upgraded to `os-js@2.0.0-rc.1`
- Upgraded to `process-js@2.0.0-rc.1`
- Upgraded to `shell-js@2.0.0-rc.1`
- Upgraded to `store-js@2.0.0-rc.1`
- Upgraded to `updater-js@2.0.0-rc.1`
## \[2.0.0-rc.1] ## \[2.0.0-rc.1]
### Dependencies ### Dependencies

@ -3,5 +3,5 @@
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
window.__TAURI_ISOLATION_HOOK__ = (payload) => { window.__TAURI_ISOLATION_HOOK__ = (payload) => {
return payload; return payload
}; }

@ -1,14 +1,14 @@
{ {
"compilerOptions": { "compilerOptions": {
"moduleResolution": "node", "moduleResolution": "bundler",
"target": "esnext", "target": "ESNext",
"module": "esnext", "module": "ESNext",
/** /**
* svelte-preprocess cannot figure out whether you have * svelte-preprocess cannot figure out whether you have
* a value or a type, so tell TypeScript to enforce using * a value or a type, so tell TypeScript to enforce using
* `import type` instead of `import` for Types. * `import type` instead of `import` for Types.
*/ */
"importsNotUsedAsValues": "error", "verbatimModuleSyntax": true,
"isolatedModules": true, "isolatedModules": true,
"resolveJsonModule": true, "resolveJsonModule": true,
/** /**
@ -18,8 +18,6 @@
"sourceMap": true, "sourceMap": true,
"esModuleInterop": true, "esModuleInterop": true,
"skipLibCheck": true, "skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"baseUrl": ".",
/** /**
* Typecheck JS in `.svelte` and `.js` files by default. * Typecheck JS in `.svelte` and `.js` files by default.
* Disable this if you'd like to use dynamic types. * Disable this if you'd like to use dynamic types.

@ -1,40 +1,44 @@
{ {
"name": "svelte-app", "name": "api",
"private": true, "private": true,
"version": "2.0.0-rc.1", "version": "2.0.9",
"type": "module", "type": "module",
"scripts": { "scripts": {
"dev": "vite --clearScreen false", "dev": "vite --clearScreen false",
"build": "vite build", "build": "vite build",
"serve": "vite preview" "serve": "vite preview",
"tauri": "tauri"
}, },
"dependencies": { "dependencies": {
"@tauri-apps/api": "2.0.0-rc.1", "@tauri-apps/api": "2.2.0",
"@tauri-apps/plugin-barcode-scanner": "2.0.0-rc.0", "@tauri-apps/plugin-barcode-scanner": "^2.2.0",
"@tauri-apps/plugin-biometric": "2.0.0-rc.0", "@tauri-apps/plugin-biometric": "^2.2.0",
"@tauri-apps/plugin-cli": "2.0.0-rc.0", "@tauri-apps/plugin-cli": "^2.2.0",
"@tauri-apps/plugin-clipboard-manager": "2.0.0-rc.0", "@tauri-apps/plugin-clipboard-manager": "^2.2.0",
"@tauri-apps/plugin-dialog": "2.0.0-rc.0", "@tauri-apps/plugin-dialog": "^2.2.0",
"@tauri-apps/plugin-fs": "2.0.0-rc.1", "@tauri-apps/plugin-fs": "^2.2.0",
"@tauri-apps/plugin-global-shortcut": "2.0.0-rc.0", "@tauri-apps/plugin-geolocation": "^2.2.0",
"@tauri-apps/plugin-http": "2.0.0-rc.1", "@tauri-apps/plugin-global-shortcut": "^2.2.0",
"@tauri-apps/plugin-nfc": "2.0.0-rc.0", "@tauri-apps/plugin-opener": "^2.2.0",
"@tauri-apps/plugin-notification": "2.0.0-rc.0", "@tauri-apps/plugin-haptics": "^2.2.0",
"@tauri-apps/plugin-os": "2.0.0-rc.0", "@tauri-apps/plugin-http": "^2.2.0",
"@tauri-apps/plugin-process": "2.0.0-rc.0", "@tauri-apps/plugin-nfc": "^2.2.0",
"@tauri-apps/plugin-shell": "2.0.0-rc.0", "@tauri-apps/plugin-notification": "^2.2.0",
"@tauri-apps/plugin-store": "2.0.0-rc.0", "@tauri-apps/plugin-os": "^2.2.0",
"@tauri-apps/plugin-updater": "2.0.0-rc.0", "@tauri-apps/plugin-process": "^2.2.0",
"@zerodevx/svelte-json-view": "1.0.9" "@tauri-apps/plugin-shell": "^2.2.0",
"@tauri-apps/plugin-store": "^2.2.0",
"@tauri-apps/plugin-updater": "^2.2.0",
"@zerodevx/svelte-json-view": "1.0.11"
}, },
"devDependencies": { "devDependencies": {
"@iconify-json/codicon": "^1.1.37", "@iconify-json/codicon": "^1.2.6",
"@iconify-json/ph": "^1.1.8", "@iconify-json/ph": "^1.2.1",
"@sveltejs/vite-plugin-svelte": "^3.0.1", "@sveltejs/vite-plugin-svelte": "^5.0.1",
"@tauri-apps/cli": "2.0.0-rc.6", "@tauri-apps/cli": "2.2.4",
"@unocss/extractor-svelte": "^0.62.0", "@unocss/extractor-svelte": "^65.0.0",
"svelte": "^4.2.8", "svelte": "^5.10.0",
"unocss": "^0.62.0", "unocss": "^65.0.0",
"vite": "^5.0.13" "vite": "^6.0.3"
} }
} }

@ -1,5 +1,235 @@
# Changelog # Changelog
## \[2.0.13]
### Dependencies
- Upgraded to `geolocation@2.2.1`
- Upgraded to `haptics@2.2.1`
## \[2.0.12]
### Dependencies
- Upgraded to `opener@2.2.3`
- Upgraded to `updater@2.3.1`
## \[2.0.11]
### Dependencies
- Upgraded to `opener@2.2.2`
## \[2.0.10]
### Dependencies
- Upgraded to `updater@2.3.0`
- Upgraded to `opener@2.2.1`
## \[2.0.9]
### Dependencies
- Upgraded to `barcode-scanner@2.1.0`
- Upgraded to `biometric@2.1.0`
- Upgraded to `cli@2.1.0`
- Upgraded to `clipboard-manager@2.1.0`
- Upgraded to `dialog@2.1.0`
- Upgraded to `fs@2.2.0`
- Upgraded to `geolocation@2.1.0`
- Upgraded to `global-shortcut@2.1.0`
- Upgraded to `haptics@2.1.0`
- Upgraded to `http@2.1.0`
- Upgraded to `log@2.1.0`
- Upgraded to `nfc@2.1.0`
- Upgraded to `notification@2.1.0`
- Upgraded to `opener@2.1.0`
- Upgraded to `os@2.1.0`
- Upgraded to `process@2.1.0`
- Upgraded to `shell@2.1.0`
- Upgraded to `store@2.2.0`
- Upgraded to `updater@2.2.0`
## \[2.0.8]
### Dependencies
- Upgraded to `fs@2.1.1`
- Upgraded to `dialog@2.0.5`
- Upgraded to `http@2.0.5`
## \[2.0.7]
### Dependencies
- Upgraded to `log@2.0.4`
## \[2.0.6]
### Dependencies
- Upgraded to `fs@2.1.0`
- Upgraded to `updater@2.1.0`
- Upgraded to `dialog@2.0.4`
- Upgraded to `log-plugin@2.0.3`
- Upgraded to `http@2.0.4`
- Upgraded to `opener@2.0.0`
## \[2.0.5]
### Dependencies
- Upgraded to `clipboard-manager@2.0.2`
- Upgraded to `log-plugin@2.0.2`
## \[2.0.4]
### Dependencies
- Upgraded to `fs@2.0.3`
- Upgraded to `dialog@2.0.3`
- Upgraded to `http@2.0.3`
## \[2.0.3]
### Dependencies
- Upgraded to `dialog@2.0.2`
- Upgraded to `fs@2.0.2`
- Upgraded to `http@2.0.2`
- Upgraded to `shell@2.0.2`
- Upgraded to `store@2.1.0`
## \[2.0.2]
- [`a1a82208`](https://github.com/tauri-apps/plugins-workspace/commit/a1a82208ed4ab87f83310be0dc95428aec9ab241) ([#1873](https://github.com/tauri-apps/plugins-workspace/pull/1873) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Downgrade MSRV to 1.77.2 to support Windows 7.
### Dependencies
- Upgraded to `barcode-scanner@2.0.1`
- Upgraded to `biometric@2.0.1`
- Upgraded to `cli@2.0.1`
- Upgraded to `clipboard-manager@2.0.1`
- Upgraded to `fs@2.0.1`
- Upgraded to `dialog@2.0.1`
- Upgraded to `geolocation@2.0.1`
- Upgraded to `global-shortcut@2.0.1`
- Upgraded to `haptics@2.0.1`
- Upgraded to `http@2.0.1`
- Upgraded to `log-plugin@2.0.1`
- Upgraded to `nfc@2.0.1`
- Upgraded to `notification@2.0.1`
- Upgraded to `os@2.0.1`
- Upgraded to `process@2.0.1`
- Upgraded to `shell@2.0.1`
- Upgraded to `store@2.0.1`
- Upgraded to `updater@2.0.2`
## \[2.0.1]
### Dependencies
- Upgraded to `updater@2.0.1`
## \[2.0.0]
- [`e2c4dfb6`](https://github.com/tauri-apps/plugins-workspace/commit/e2c4dfb6af43e5dd8d9ceba232c315f5febd55c1) Update to tauri v2 stable release.
### Dependencies
- Upgraded to `barcode-scanner@2.0.0`
- Upgraded to `biometric@2.0.0`
- Upgraded to `cli@2.0.0`
- Upgraded to `clipboard-manager@2.0.0`
- Upgraded to `fs@2.0.0`
- Upgraded to `dialog@2.0.0`
- Upgraded to `global-shortcut@2.0.0`
- Upgraded to `http@2.0.0`
- Upgraded to `log-plugin@2.0.0`
- Upgraded to `nfc@2.0.0`
- Upgraded to `notification@2.0.0`
- Upgraded to `os@2.0.0`
- Upgraded to `process@2.0.0`
- Upgraded to `shell@2.0.0`
- Upgraded to `store@2.0.0`
- Upgraded to `updater@2.0.0`
## \[2.0.0-rc.8]
### Dependencies
- Upgraded to `cli@2.0.0-rc.2`
- Upgraded to `dialog@2.0.0-rc.8`
- Upgraded to `fs@2.0.0-rc.6`
- Upgraded to `shell@2.0.0-rc.4`
- Upgraded to `store@2.0.0-rc.4`
- Upgraded to `updater@2.0.0-rc.4`
- Upgraded to `http@2.0.0-rc.6`
## \[2.0.0-rc.7]
### Dependencies
- Upgraded to `clipboard-manager@2.0.0-rc.4`
- Upgraded to `fs@2.0.0-rc.5`
- Upgraded to `notification@2.0.0-rc.5`
- Upgraded to `dialog@2.0.0-rc.7`
- Upgraded to `http@2.0.0-rc.5`
## \[2.0.0-rc.6]
### Dependencies
- Upgraded to `dialog@2.0.0-rc.6`
- Upgraded to `fs@2.0.0-rc.4`
- Upgraded to `http@2.0.0-rc.4`
## \[2.0.0-rc.5]
### Dependencies
- Upgraded to `barcode-scanner@2.0.0-rc.4`
- Upgraded to `notification@2.0.0-rc.4`
## \[2.0.0-rc.4]
### Dependencies
- Upgraded to `fs@2.0.0-rc.3`
- Upgraded to `dialog@2.0.0-rc.5`
- Upgraded to `updater@2.0.0-rc.3`
- Upgraded to `http@2.0.0-rc.3`
## \[2.0.0-rc.3]
### Dependencies
- Upgraded to `fs@2.0.0-rc.2`
- Upgraded to `dialog@2.0.0-rc.4`
- Upgraded to `http@2.0.0-rc.2`
## \[2.0.0-rc.2]
### Dependencies
- Upgraded to `barcode-scanner@2.0.0-rc.3`
- Upgraded to `notification@2.0.0-rc.3`
- Upgraded to `dialog@2.0.0-rc.3`
- Upgraded to `fs@2.0.0-rc.1`
- Upgraded to `global-shortcut@2.0.0-rc.2`
- Upgraded to `store@2.0.0-rc.3`
- Upgraded to `biometric@2.0.0-rc.3`
- Upgraded to `cli@2.0.0-rc.1`
- Upgraded to `clipboard-manager@2.0.0-rc.3`
- Upgraded to `http@2.0.0-rc.1`
- Upgraded to `log-plugin@2.0.0-rc.2`
- Upgraded to `nfc@2.0.0-rc.3`
- Upgraded to `os@2.0.0-rc.1`
- Upgraded to `process@2.0.0-rc.1`
- Upgraded to `shell@2.0.0-rc.3`
- Upgraded to `updater@2.0.0-rc.2`
## \[2.0.0-rc.1] ## \[2.0.0-rc.1]
### Dependencies ### Dependencies

@ -1,7 +1,7 @@
[package] [package]
name = "api" name = "api"
publish = false publish = false
version = "2.0.0-rc.1" version = "2.0.13"
description = "An example Tauri Application showcasing the api" description = "An example Tauri Application showcasing the api"
edition = "2021" edition = "2021"
rust-version = { workspace = true } rust-version = { workspace = true }
@ -19,22 +19,23 @@ serde_json = { workspace = true }
serde = { workspace = true } serde = { workspace = true }
tiny_http = "0.12" tiny_http = "0.12"
log = { workspace = true } log = { workspace = true }
tauri-plugin-log = { path = "../../../plugins/log", version = "2.0.0-rc.1" } tauri-plugin-log = { path = "../../../plugins/log", version = "2.2.0" }
tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.0.0-rc.0", features = [ tauri-plugin-fs = { path = "../../../plugins/fs", version = "2.2.0", features = [
"watch", "watch",
] } ] }
tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.0.0-rc.2" } tauri-plugin-clipboard-manager = { path = "../../../plugins/clipboard-manager", version = "2.2.0" }
tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.0.0-rc.2" } tauri-plugin-dialog = { path = "../../../plugins/dialog", version = "2.2.0" }
tauri-plugin-http = { path = "../../../plugins/http", features = [ tauri-plugin-http = { path = "../../../plugins/http", features = [
"multipart", "multipart",
], version = "2.0.0-rc.0" } ], version = "2.2.0" }
tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.0.0-rc.2", features = [ tauri-plugin-notification = { path = "../../../plugins/notification", version = "2.2.0", features = [
"windows7-compat", "windows7-compat",
] } ] }
tauri-plugin-os = { path = "../../../plugins/os", version = "2.0.0-rc.0" } tauri-plugin-os = { path = "../../../plugins/os", version = "2.2.0" }
tauri-plugin-process = { path = "../../../plugins/process", version = "2.0.0-rc.0" } tauri-plugin-process = { path = "../../../plugins/process", version = "2.2.0" }
tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.0.0-rc.2" } tauri-plugin-opener = { path = "../../../plugins/opener", version = "2.2.3" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.0.0-rc.2" } tauri-plugin-shell = { path = "../../../plugins/shell", version = "2.2.0" }
tauri-plugin-store = { path = "../../../plugins/store", version = "2.2.0" }
[dependencies.tauri] [dependencies.tauri]
workspace = true workspace = true
@ -50,17 +51,17 @@ features = [
] ]
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.0.0-rc.0" } tauri-plugin-cli = { path = "../../../plugins/cli", version = "2.2.0" }
tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.0.0-rc.1" } tauri-plugin-global-shortcut = { path = "../../../plugins/global-shortcut", version = "2.2.0" }
tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.0.0-rc.1" } tauri-plugin-updater = { path = "../../../plugins/updater", version = "2.3.1" }
tauri-plugin-window-state = { path = "../../../plugins/window-state", version = "2.2.0" }
[target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies] [target."cfg(any(target_os = \"android\", target_os = \"ios\"))".dependencies]
tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.0.0-rc.2" } tauri-plugin-barcode-scanner = { path = "../../../plugins/barcode-scanner/", version = "2.2.0" }
tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.0.0-rc.2" } tauri-plugin-nfc = { path = "../../../plugins/nfc", version = "2.2.0" }
tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.0.0-rc.2" } tauri-plugin-biometric = { path = "../../../plugins/biometric/", version = "2.2.0" }
tauri-plugin-geolocation = { path = "../../../plugins/geolocation/", version = "2.2.1" }
[target."cfg(target_os = \"windows\")".dependencies] tauri-plugin-haptics = { path = "../../../plugins/haptics/", version = "2.2.1" }
window-shadows = "0.2"
[features] [features]
prod = ["tauri/custom-protocol"] prod = ["tauri/custom-protocol"]

@ -1,10 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Request camera access for WebRTC</string> <string>Request camera access for WebRTC</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>Request microphone access for WebRTC</string> <string>Request microphone access for WebRTC</string>
</dict> <key>NSFaceIDUsageDescription</key>
<string>Authenticate with biometrics</string>
<key>NFCReaderUsageDescription</key>
<string>Read and write to NFC tags for testing</string>
</dict>
</plist> </plist>

@ -53,6 +53,7 @@
} }
] ]
}, },
"shell:allow-open",
"shell:allow-kill", "shell:allow-kill",
"shell:allow-stdin-write", "shell:allow-stdin-write",
"process:allow-exit", "process:allow-exit",
@ -79,10 +80,11 @@
], ],
"deny": ["$APPDATA/db/*.stronghold"] "deny": ["$APPDATA/db/*.stronghold"]
}, },
"store:allow-entries", "store:default",
"store:allow-get", "opener:default",
"store:allow-set", {
"store:allow-save", "identifier": "opener:allow-open-path",
"store:allow-load" "allow": [{ "path": "$APPDATA" }, { "path": "$APPDATA/**" }]
}
] ]
} }

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

@ -11,6 +11,14 @@
"barcode-scanner:allow-scan", "barcode-scanner:allow-scan",
"barcode-scanner:allow-cancel", "barcode-scanner:allow-cancel",
"barcode-scanner:allow-request-permissions", "barcode-scanner:allow-request-permissions",
"barcode-scanner:allow-check-permissions" "barcode-scanner:allow-check-permissions",
"geolocation:allow-check-permissions",
"geolocation:allow-request-permissions",
"geolocation:allow-watch-position",
"geolocation:allow-get-current-position",
"haptics:allow-impact-feedback",
"haptics:allow-notification-feedback",
"haptics:allow-selection-feedback",
"haptics:allow-vibrate"
] ]
} }

@ -19,7 +19,7 @@
<option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" /> <option name="gradleJvm" value="#GRADLE_LOCAL_JAVA_HOME" />
<option name="modules"> <option name="modules">
<set> <set>
<option value="$USER_HOME$/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tauri-2.0.0-rc.2/mobile/android" /> <option value="$USER_HOME$/.cargo/registry/src/index.crates.io-6f17d22bba15001f/tauri-2.0.2/mobile/android" />
<option value="$PROJECT_DIR$" /> <option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" /> <option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/buildSrc" /> <option value="$PROJECT_DIR$/buildSrc" />
@ -28,6 +28,8 @@
<option value="$PROJECT_DIR$/../../../../../plugins/clipboard-manager/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/clipboard-manager/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/dialog/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/dialog/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/fs/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/fs/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/geolocation/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/haptics/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/nfc/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/nfc/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/notification/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/notification/android" />
<option value="$PROJECT_DIR$/../../../../../plugins/shell/android" /> <option value="$PROJECT_DIR$/../../../../../plugins/shell/android" />

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project version="4"> <project version="4">
<component name="KotlinJpsPluginSettings"> <component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" /> <option name="version" value="1.9.25" />
</component> </component>
</project> </project>

@ -19,7 +19,8 @@ android {
defaultConfig { defaultConfig {
manifestPlaceholders["usesCleartextTraffic"] = "false" manifestPlaceholders["usesCleartextTraffic"] = "false"
applicationId = "com.tauri.api" applicationId = "com.tauri.api"
minSdk = 24 minSdk = 24
targetSdk = 34
versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt() versionCode = tauriProperties.getProperty("tauri.android.versionCode", "1").toInt()
versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0") versionName = tauriProperties.getProperty("tauri.android.versionName", "1.0")
} }
@ -47,6 +48,9 @@ android {
kotlinOptions { kotlinOptions {
jvmTarget = "1.8" jvmTarget = "1.8"
} }
buildFeatures {
buildConfig = true
}
} }
rust { rust {

@ -1,6 +1,10 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"> <manifest xmlns:android="http://schemas.android.com/apk/res/android">
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.INTERNET" />
<!-- AndroidTV support -->
<uses-feature android:name="android.software.leanback" android:required="false" />
<application <application
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
@ -15,6 +19,8 @@
<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" />
<!-- AndroidTV support -->
<category android:name="android.intent.category.LEANBACK_LAUNCHER" />
</intent-filter> </intent-filter>
<!-- NFC PLUGIN. AUTO-GENERATED. DO NOT REMOVE. --> <!-- NFC PLUGIN. AUTO-GENERATED. DO NOT REMOVE. -->
<intent-filter> <intent-filter>

@ -4,8 +4,8 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath("com.android.tools.build:gradle:8.3.2") classpath("com.android.tools.build:gradle:8.5.1")
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.21") classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.25")
} }
} }

@ -18,6 +18,6 @@ repositories {
dependencies { dependencies {
compileOnly(gradleApi()) compileOnly(gradleApi())
implementation("com.android.tools.build:gradle:8.3.2") implementation("com.android.tools.build:gradle:8.5.1")
} }

@ -21,5 +21,4 @@ kotlin.code.style=official
# 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 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-8.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

@ -1,89 +1,89 @@
@rem @rem
@rem Copyright 2015 the original author or authors. @rem Copyright 2015 the original author or authors.
@rem @rem
@rem Licensed under the Apache License, Version 2.0 (the "License"); @rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License. @rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at @rem You may obtain a copy of the License at
@rem @rem
@rem https://www.apache.org/licenses/LICENSE-2.0 @rem https://www.apache.org/licenses/LICENSE-2.0
@rem @rem
@rem Unless required by applicable law or agreed to in writing, software @rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS, @rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and @rem See the License for the specific language governing permissions and
@rem limitations under the License. @rem limitations under the License.
@rem @rem
@if "%DEBUG%" == "" @echo off @if "%DEBUG%" == "" @echo off
@rem ########################################################################## @rem ##########################################################################
@rem @rem
@rem Gradle startup script for Windows @rem Gradle startup script for Windows
@rem @rem
@rem ########################################################################## @rem ##########################################################################
@rem Set local scope for the variables with windows NT shell @rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0 set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=. if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0 set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME% set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter. @rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe @rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute if "%ERRORLEVEL%" == "0" goto execute
echo. echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:findJavaFromJavaHome :findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=% set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. echo.
echo Please set the JAVA_HOME variable in your environment to match the echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. echo location of your Java installation.
goto fail goto fail
:execute :execute
@rem Setup the command line @rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle @rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end :end
@rem End local scope for the variables with windows NT shell @rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd if "%ERRORLEVEL%"=="0" goto mainEnd
:fail :fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code! rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1 exit /b 1
:mainEnd :mainEnd
if "%OS%"=="Windows_NT" endlocal if "%OS%"=="Windows_NT" endlocal
:omega :omega

@ -3,6 +3,6 @@
<plist version="1.0"> <plist version="1.0">
<dict> <dict>
<key>method</key> <key>method</key>
<string>development</string> <string>debugging</string>
</dict> </dict>
</plist> </plist>

@ -3,14 +3,14 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 54; objectVersion = 56;
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4A00E5F95D64FD14E47F85BD /* libapi_lib.a */; };
3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; }; 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */; };
328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; }; 328B4ADB3700C1873BEB7B10 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 90D3B673AFAB8D8AB561F616 /* main.mm */; };
6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; }; 6F379F15DA085785BA2624D4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 6B7E79E23E646BA7968B457C /* Assets.xcassets */; };
832F9A55FEDEF3D807D8C40A /* libapp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 248286BAA086BB1A5F98B2B2 /* libapp.a */; };
9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; }; 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 62601E25FA39E62BE119B74D /* Metal.framework */; };
9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; }; 9DDA3BE70DD0E4013973FE38 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6082E363D51372A7658C351 /* UIKit.framework */; };
AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; }; AC8BDC2C7A63FA3FDC5967F4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */; };
@ -22,26 +22,26 @@
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; path = main.rs; sourceTree = "<group>"; }; 0E96CE07CD20273DD46BF325 /* main.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = main.rs; sourceTree = "<group>"; };
1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; path = tray.rs; sourceTree = "<group>"; }; 1C1AB1B414CA2795AFBEDDB9 /* tray.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = tray.rs; sourceTree = "<group>"; };
248286BAA086BB1A5F98B2B2 /* libapp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapp.a; sourceTree = "<group>"; };
2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; }; 2F63E2AA460089BB58D40C79 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; }; 338E66700FD330B99D434DD7 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 384966E551417F94A02D2706 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; };
4A00E5F95D64FD14E47F85BD /* libapi_lib.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libapi_lib.a; sourceTree = "<group>"; };
4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; }; 4B2D1B108AE002010BDEC6D2 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = LaunchScreen.storyboard; sourceTree = "<group>"; };
59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; }; 59CFE20DCF760BE67D9CE3D6 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = System/Library/Frameworks/WebKit.framework; sourceTree = SDKROOT; };
5AC703CEBA41A121596066F3 /* api_iOS.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = api_iOS.app; sourceTree = BUILT_PRODUCTS_DIR; }; 5AC703CEBA41A121596066F3 /* Tauri API.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Tauri API.app"; sourceTree = BUILT_PRODUCTS_DIR; };
62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; }; 62601E25FA39E62BE119B74D /* Metal.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Metal.framework; path = System/Library/Frameworks/Metal.framework; sourceTree = SDKROOT; };
6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; 6B7E79E23E646BA7968B457C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; }; 74A8FDFB350B966F5AAD4A24 /* assets */ = {isa = PBXFileReference; lastKnownFileType = folder; path = assets; sourceTree = SOURCE_ROOT; };
785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; path = lib.rs; sourceTree = "<group>"; }; 785D025E9542F7E098BF22B5 /* lib.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = lib.rs; sourceTree = "<group>"; };
879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = "<group>"; }; 879941AE3DAA14534BBC6391 /* api_iOS.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = api_iOS.entitlements; sourceTree = "<group>"; };
90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; }; 90D3B673AFAB8D8AB561F616 /* main.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; B6082E363D51372A7658C351 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; };
DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; }; DC377692DC31A070A0188C9D /* QuartzCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = QuartzCore.framework; path = System/Library/Frameworks/QuartzCore.framework; sourceTree = SDKROOT; };
EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = "<group>"; }; EC8C7948C50C3C9B5D96CB61 /* bindings.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bindings.h; sourceTree = "<group>"; };
F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; path = cmd.rs; sourceTree = "<group>"; }; F835F52713CE8F029D5D252C /* cmd.rs */ = {isa = PBXFileReference; lastKnownFileType = text; path = cmd.rs; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@ -49,7 +49,7 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
2B78BA327A38C76093D36092 /* libapi_lib.a in Frameworks */, 832F9A55FEDEF3D807D8C40A /* libapp.a in Frameworks */,
3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */, 3043432501C9BC2DB6B4CB95 /* CoreGraphics.framework in Frameworks */,
9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */, 9AADB041D25772D04E543F15 /* Metal.framework in Frameworks */,
DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */, DFFF888045C8D9D9FB69E8FD /* MetalKit.framework in Frameworks */,
@ -90,7 +90,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */, 71EB788DE4662CFC0D97F567 /* CoreGraphics.framework */,
4A00E5F95D64FD14E47F85BD /* libapi_lib.a */, 248286BAA086BB1A5F98B2B2 /* libapp.a */,
62601E25FA39E62BE119B74D /* Metal.framework */, 62601E25FA39E62BE119B74D /* Metal.framework */,
338E66700FD330B99D434DD7 /* MetalKit.framework */, 338E66700FD330B99D434DD7 /* MetalKit.framework */,
DC377692DC31A070A0188C9D /* QuartzCore.framework */, DC377692DC31A070A0188C9D /* QuartzCore.framework */,
@ -104,7 +104,7 @@
4AC51E67B71E27F15B02C5CD /* Products */ = { 4AC51E67B71E27F15B02C5CD /* Products */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5AC703CEBA41A121596066F3 /* api_iOS.app */, 5AC703CEBA41A121596066F3 /* Tauri API.app */,
); );
name = Products; name = Products;
sourceTree = "<group>"; sourceTree = "<group>";
@ -172,7 +172,7 @@
); );
name = api_iOS; name = api_iOS;
productName = api_iOS; productName = api_iOS;
productReference = 5AC703CEBA41A121596066F3 /* api_iOS.app */; productReference = 5AC703CEBA41A121596066F3 /* Tauri API.app */;
productType = "com.apple.product-type.application"; productType = "com.apple.product-type.application";
}; };
/* End PBXNativeTarget section */ /* End PBXNativeTarget section */
@ -186,7 +186,6 @@
TargetAttributes = { TargetAttributes = {
54DC6E273C78071F3BA12EF3 = { 54DC6E273C78071F3BA12EF3 = {
DevelopmentTeam = Q93MBH6S2F; DevelopmentTeam = Q93MBH6S2F;
ProvisioningStyle = Automatic;
}; };
}; };
}; };
@ -235,9 +234,9 @@
outputFileListPaths = ( outputFileListPaths = (
); );
outputPaths = ( outputPaths = (
"$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a", "$(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a",
"$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a", "$(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a",
"$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a", "$(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a",
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
@ -397,13 +396,32 @@
"\".\"", "\".\"",
); );
INFOPLIST_FILE = api_iOS/Info.plist; INFOPLIST_FILE = api_iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "$(inherited)",
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
PRODUCT_NAME = "Tauri API"; PRODUCT_NAME = "Tauri API";
SDKROOT = iphoneos; SDKROOT = iphoneos;
@ -433,13 +451,32 @@
"\".\"", "\".\"",
); );
INFOPLIST_FILE = api_iOS/Info.plist; INFOPLIST_FILE = api_iOS/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = ( LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)", "$(inherited)",
"@executable_path/Frameworks", "@executable_path/Frameworks",
); );
"LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "LIBRARY_SEARCH_PATHS[arch=arm64-sim]" = (
"LIBRARY_SEARCH_PATHS[arch=arm64]" = "$(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "$(inherited)",
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = "$(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)"; "$(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=arm64]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
"LIBRARY_SEARCH_PATHS[arch=x86_64]" = (
"$(inherited)",
"$(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION)",
"$(SDKROOT)/usr/lib/swift",
"$(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME)",
"$(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)",
);
PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api; PRODUCT_BUNDLE_IDENTIFIER = com.tauri.api;
PRODUCT_NAME = "Tauri API"; PRODUCT_NAME = "Tauri API";
SDKROOT = iphoneos; SDKROOT = iphoneos;

@ -40,9 +40,13 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>NSFaceIDUsageDescription</key>
<string>Authenticate with biometrics</string>
<key>NSCameraUsageDescription</key> <key>NSCameraUsageDescription</key>
<string>Request camera access for WebRTC</string> <string>Request camera access for WebRTC</string>
<key>NSMicrophoneUsageDescription</key> <key>NSMicrophoneUsageDescription</key>
<string>Request microphone access for WebRTC</string> <string>Request microphone access for WebRTC</string>
<key>NFCReaderUsageDescription</key>
<string>Read and write to NFC tags for testing</string>
</dict> </dict>
</plist> </plist>

@ -2,7 +2,7 @@ name: api
options: options:
bundleIdPrefix: com.tauri.api bundleIdPrefix: com.tauri.api
deploymentTarget: deploymentTarget:
iOS: 13.0 iOS: 14.0
fileGroups: [../../src] fileGroups: [../../src]
configs: configs:
debug: debug debug: debug
@ -13,7 +13,6 @@ settingGroups:
PRODUCT_NAME: Tauri API PRODUCT_NAME: Tauri API
PRODUCT_BUNDLE_IDENTIFIER: com.tauri.api PRODUCT_BUNDLE_IDENTIFIER: com.tauri.api
DEVELOPMENT_TEAM: Q93MBH6S2F DEVELOPMENT_TEAM: Q93MBH6S2F
CODE_SIGN_STYLE: Automatic
targetTemplates: targetTemplates:
app: app:
type: application type: application
@ -65,7 +64,7 @@ targets:
base: base:
ENABLE_BITCODE: false ENABLE_BITCODE: false
ARCHS: [arm64, arm64-sim] ARCHS: [arm64, arm64-sim]
VALID_ARCHS: arm64 arm64-sim VALID_ARCHS: arm64 arm64-sim
LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) LIBRARY_SEARCH_PATHS[arch=x86_64]: $(inherited) $(PROJECT_DIR)/Externals/x86_64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) LIBRARY_SEARCH_PATHS[arch=arm64]: $(inherited) $(PROJECT_DIR)/Externals/arm64/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME) LIBRARY_SEARCH_PATHS[arch=arm64-sim]: $(inherited) $(PROJECT_DIR)/Externals/arm64-sim/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
@ -74,7 +73,7 @@ targets:
EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64 EXCLUDED_ARCHS[sdk=iphoneos*]: arm64-sim x86_64
groups: [app] groups: [app]
dependencies: dependencies:
- framework: libapi_lib.a - framework: libapp.a
embed: false embed: false
- sdk: CoreGraphics.framework - sdk: CoreGraphics.framework
- sdk: Metal.framework - sdk: Metal.framework
@ -88,6 +87,6 @@ targets:
name: Build Rust Code name: Build Rust Code
basedOnDependencyAnalysis: false basedOnDependencyAnalysis: false
outputFiles: outputFiles:
- $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapi_lib.a - $(SRCROOT)/Externals/x86_64/${CONFIGURATION}/libapp.a
- $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapi_lib.a - $(SRCROOT)/Externals/arm64/${CONFIGURATION}/libapp.a
- $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapi_lib.a - $(SRCROOT)/Externals/arm64-sim/${CONFIGURATION}/libapp.a

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -36,6 +36,7 @@ pub fn run() {
.plugin(tauri_plugin_notification::init()) .plugin(tauri_plugin_notification::init())
.plugin(tauri_plugin_os::init()) .plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_process::init()) .plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_store::Builder::default().build()) .plugin(tauri_plugin_store::Builder::default().build())
.setup(move |app| { .setup(move |app| {
@ -45,6 +46,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_window_state::Builder::new().build())?;
app.handle() app.handle()
.plugin(tauri_plugin_updater::Builder::new().build())?; .plugin(tauri_plugin_updater::Builder::new().build())?;
} }
@ -53,6 +56,8 @@ pub fn run() {
app.handle().plugin(tauri_plugin_barcode_scanner::init())?; app.handle().plugin(tauri_plugin_barcode_scanner::init())?;
app.handle().plugin(tauri_plugin_nfc::init())?; app.handle().plugin(tauri_plugin_nfc::init())?;
app.handle().plugin(tauri_plugin_biometric::init())?; app.handle().plugin(tauri_plugin_biometric::init())?;
app.handle().plugin(tauri_plugin_geolocation::init())?;
app.handle().plugin(tauri_plugin_haptics::init())?;
} }
let mut webview_window_builder = let mut webview_window_builder =
@ -64,7 +69,7 @@ pub fn run() {
.title("Tauri API Validation") .title("Tauri API Validation")
.inner_size(1000., 800.) .inner_size(1000., 800.)
.min_inner_size(600., 400.) .min_inner_size(600., 400.)
.content_protected(true); .visible(false);
} }
#[cfg(target_os = "windows")] #[cfg(target_os = "windows")]

@ -1,5 +1,5 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "Tauri API", "productName": "Tauri API",
"version": "2.0.0", "version": "2.0.0",
"identifier": "com.tauri.api", "identifier": "com.tauri.api",
@ -100,6 +100,9 @@
} }
} }
} }
},
"iOS": {
"minimumSystemVersion": "14.0"
} }
} }
} }

@ -1,206 +1,222 @@
<script> <script>
import { writable } from "svelte/store"; import { writable } from 'svelte/store'
import { open } from "@tauri-apps/plugin-shell"; import { getCurrentWindow } from '@tauri-apps/api/window'
import { getCurrentWindow } from "@tauri-apps/api/window"; import { getCurrentWebview } from '@tauri-apps/api/webview'
import { getCurrentWebview } from "@tauri-apps/api/webview"; import * as os from '@tauri-apps/plugin-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 Shortcuts from './views/Shortcuts.svelte'
import Shortcuts from "./views/Shortcuts.svelte"; import Shell from './views/Shell.svelte'
import Shell from "./views/Shell.svelte"; import Opener from './views/Opener.svelte'
import Store from "./views/Store.svelte"; import Store from './views/Store.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 Biometric from "./views/Biometric.svelte"; import Biometric from './views/Biometric.svelte'
import Geolocation from './views/Geolocation.svelte'
import { onMount, tick } from "svelte"; import Haptics from './views/Haptics.svelte'
import { ask } from "@tauri-apps/plugin-dialog";
import Nfc from "./views/Nfc.svelte"; import { onMount, tick } from 'svelte'
import { ask } from '@tauri-apps/plugin-dialog'
const appWindow = getCurrentWindow(); import Nfc from './views/Nfc.svelte'
if (appWindow.label !== "main") { const appWindow = getCurrentWindow()
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()
} }
}); })
} }
getCurrentWebview().onDragDropEvent((event) => { getCurrentWebview().onDragDropEvent((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 = const isMobile = userAgent.includes('android') || userAgent.includes('iphone')
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'
}, },
{ {
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'
}, },
{ {
label: "Notifications", label: 'Notifications',
component: Notifications, component: Notifications,
icon: "i-codicon-bell-dot", icon: 'i-codicon-bell-dot'
}, },
!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'
}, },
{ {
label: "Store", label: 'Opener',
component: Opener,
icon: 'i-codicon-link-external'
},
{
label: 'Store',
component: Store, component: Store,
icon: "i-codicon-file-code", icon: 'i-codicon-file-code'
}, },
!isMobile && { !isMobile && {
label: "Updater", label: 'Updater',
component: Updater, component: Updater,
icon: "i-codicon-cloud-download", icon: 'i-codicon-cloud-download'
}, },
{ {
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'
}, },
isMobile && { isMobile && {
label: "NFC", label: 'NFC',
component: Nfc, component: Nfc,
icon: "i-ph-nfc", icon: 'i-ph-nfc'
}, },
isMobile && { isMobile && {
label: "Biometric", label: 'Biometric',
component: Biometric, component: Biometric,
icon: "i-ph-scan", icon: 'i-ph-scan'
},
isMobile && {
label: 'Geolocation',
component: Geolocation,
icon: 'i-ph-map-pin'
}, },
]; isMobile && {
label: 'Haptics',
component: Haptics,
icon: 'i-ph-vibrate'
}
]
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 () => {
isWindowMaximized = await appWindow.isMaximized(); isWindowMaximized = await appWindow.isMaximized()
appWindow.onResized(async () => { appWindow.onResized(async () => {
isWindowMaximized = await appWindow.isMaximized(); isWindowMaximized = await appWindow.isMaximized()
}); })
}); })
function minimize() { function minimize() {
appWindow.minimize(); appWindow.minimize()
} }
async function toggleMaximize() { async function toggleMaximize() {
(await appWindow.isMaximized()) ;(await appWindow.isMaximized())
? appWindow.unmaximize() ? appWindow.unmaximize()
: appWindow.maximize(); : appWindow.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) {
appWindow.close(); appWindow.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([])
let consoleTextEl; let consoleTextEl
async function onMessage(value) { async function onMessage(value) {
messages.update((r) => [ messages.update((r) => [
...r, ...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>'
}, }
]); ])
await tick(); await tick()
if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight; if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight
} }
// this function is renders HTML without sanitizing it so it's insecure // this function renders HTML without sanitizing it so it's insecure
// we only use it with our own input data // we only use it with our own input data
async function insecureRenderHtml(html) { async function insecureRenderHtml(html) {
messages.update((r) => [ messages.update((r) => [
@ -209,111 +225,109 @@
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>'
}, }
]); ])
await tick(); await tick()
if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight; if (consoleTextEl) consoleTextEl.scrollTop = consoleTextEl.scrollHeight
} }
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()) === "windows"; isWindows = (await os.platform()) === 'windows'
}); })
// 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 isSideBarOpen = isSideBarOpen ? delta > -(18.75 / 2) : delta > 18.75 / 2
? 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>
@ -331,42 +345,46 @@
children:h-100% children:w-12 children:inline-flex children:h-100% children:w-12 children:inline-flex
children:items-center children:justify-center" children:items-center children:justify-center"
> >
<span <button
title={isDark ? "Switch to Light mode" : "Switch to Dark mode"} aria-label="Toggle dark mode"
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" title={isDark ? 'Switch to Light mode' : 'Switch to Dark mode'}
class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleDark} on:click={toggleDark}
> >
{#if isDark} {#if isDark}
<div class="i-ph-sun" /> <div class="i-ph-sun"></div>
{:else} {:else}
<div class="i-ph-moon" /> <div class="i-ph-moon"></div>
{/if} {/if}
</span> </button>
<span <button
aria-label="Minimize window"
title="Minimize" title="Minimize"
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={minimize} on:click={minimize}
> >
<div class="i-codicon-chrome-minimize" /> <div class="i-codicon-chrome-minimize"></div>
</span> </button>
<span <button
title={isWindowMaximized ? "Restore" : "Maximize"} aria-label="Maximize window"
class="hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker" title={isWindowMaximized ? 'Restore' : 'Maximize'}
class="bg-inherit border-none hover:bg-hoverOverlay active:bg-hoverOverlayDarker dark:hover:bg-darkHoverOverlay dark:active:bg-darkHoverOverlayDarker"
on:click={toggleMaximize} on:click={toggleMaximize}
> >
{#if isWindowMaximized} {#if isWindowMaximized}
<div class="i-codicon-chrome-restore" /> <div class="i-codicon-chrome-restore"></div>
{:else} {:else}
<div class="i-codicon-chrome-maximize" /> <div class="i-codicon-chrome-maximize"></div>
{/if} {/if}
</span> </button>
<span <button
aria-label="Close window"
title="Close" title="Close"
class="hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText" class="bg-inherit border-none hover:bg-red-700 dark:hover:bg-red-700 hover:text-darkPrimaryText active:bg-red-700/90 dark:active:bg-red-700/90 active:text-darkPrimaryText"
on:click={close} on:click={close}
> >
<div class="i-codicon-chrome-close" /> <div class="i-codicon-chrome-close"></div>
</span> </button>
</span> </span>
</div> </div>
{/if} {/if}
@ -374,13 +392,13 @@
<!-- Sidebar toggle, only visible on small screens --> <!-- Sidebar toggle, only visible on small screens -->
<div <div
id="sidebarToggle" id="sidebarToggle"
class="z-2000 sidebar-toggle display-none lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8 class="z-2000 sidebar-toggle hidden lt-sm:flex justify-center absolute items-center w-8 h-8 rd-8
bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark" bg-accent dark:bg-darkAccent active:bg-accentDark dark:active:bg-darkAccentDark"
> >
{#if isSideBarOpen} {#if isSideBarOpen}
<span class="i-codicon-close animate-duration-300ms animate-fade-in" /> <span class="i-codicon-close animate-duration-300ms animate-fade-in"></span>
{:else} {:else}
<span class="i-codicon-menu animate-duration-300ms animate-fade-in" /> <span class="i-codicon-menu animate-duration-300ms animate-fade-in"></span>
{/if} {/if}
</div> </div>
@ -392,24 +410,21 @@
class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999 class="lt-sm:h-screen lt-sm:shadow-lg lt-sm:shadow lt-sm:transition-transform lt-sm:absolute lt-sm:z-1999
bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2" bg-darkPrimaryLighter transition-colors-250 overflow-hidden grid select-none px-2"
> >
<img <a href="https://tauri.app" target="_blank">
on:click={() => open("https://tauri.app/")} <img class="p-7" src="tauri_logo.png" alt="Tauri logo" />
class="self-center p-7 cursor-pointer" </a>
src="tauri_logo.png"
alt="Tauri logo"
/>
{#if !isWindows} {#if !isWindows}
<a href="##" class="nv justify-between h-8" on:click={toggleDark}> <a href="##" class="nv justify-between h-8" on:click={toggleDark}>
{#if isDark} {#if isDark}
Switch to Light mode Switch to Light mode
<div class="i-ph-sun" /> <div class="i-ph-sun"></div>
{:else} {:else}
Switch to Dark mode Switch to Dark mode
<div class="i-ph-moon" /> <div class="i-ph-moon"></div>
{/if} {/if}
</a> </a>
<br /> <br />
<div class="bg-white/5 h-2px" /> <div class="bg-white/5 h-2px"></div>
<br /> <br />
{/if} {/if}
@ -419,7 +434,7 @@
href="https://tauri.app/v1/guides/" href="https://tauri.app/v1/guides/"
> >
Documentation Documentation
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<a <a
class="nv justify-between h-8" class="nv justify-between h-8"
@ -427,7 +442,7 @@
href="https://github.com/tauri-apps/tauri" href="https://github.com/tauri-apps/tauri"
> >
GitHub GitHub
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<a <a
class="nv justify-between h-8" class="nv justify-between h-8"
@ -435,10 +450,10 @@
href="https://github.com/tauri-apps/tauri/tree/dev/examples/api" href="https://github.com/tauri-apps/tauri/tree/dev/examples/api"
> >
Source Source
<span class="i-codicon-link-external" /> <span class="i-codicon-link-external"></span>
</a> </a>
<br /> <br />
<div class="bg-white/5 h-2px" /> <div class="bg-white/5 h-2px"></div>
<br /> <br />
<div <div
class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1" class="flex flex-col overflow-y-auto children-h-10 children-flex-none gap-1"
@ -449,11 +464,11 @@
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"></div>
<p>{view.label}</p></a <p>{view.label}</p></a
> >
{/if} {/if}
@ -482,21 +497,23 @@
id="console" id="console"
class="select-none h-15rem grid grid-rows-[2px_2rem_1fr] gap-1 overflow-hidden" class="select-none h-15rem grid grid-rows-[2px_2rem_1fr] gap-1 overflow-hidden"
> >
<!-- svelte-ignore a11y_no_static_element_interactions -->
<div <div
on:mousedown={startResizingConsole} on:mousedown={startResizingConsole}
class="bg-black/20 h-2px cursor-ns-resize" class="bg-black/20 h-2px cursor-ns-resize"
/> ></div>
<div class="flex justify-between items-center px-2"> <div class="flex justify-between items-center px-2">
<p class="font-semibold">Console</p> <p class="font-semibold">Console</p>
<div <button
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center aria-label="Clear Console"
class="cursor-pointer h-85% rd-1 p-1 flex justify-center items-center border-none bg-inherit
hover:bg-hoverOverlay dark:hover:bg-darkHoverOverlay hover:bg-hoverOverlay dark:hover:bg-darkHoverOverlay
active:bg-hoverOverlay/25 dark:active:bg-darkHoverOverlay/25 active:bg-hoverOverlay/25 dark:active:bg-darkHoverOverlay/25
" "
on:click={clear} on:click={clear}
> >
<div class="i-codicon-clear-all" /> <div class="i-codicon-clear-all"></div>
</div> </button>
</div> </div>
<div <div
bind:this={consoleTextEl} bind:this={consoleTextEl}

@ -5,7 +5,7 @@
* { * {
box-sizing: border-box; box-sizing: border-box;
font-family: "Rubik", sans-serif; font-family: 'Rubik', sans-serif;
} }
::-webkit-scrollbar { ::-webkit-scrollbar {

@ -4,12 +4,12 @@
export function arrayBufferToBase64(buffer, callback) { export 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)
} }

@ -2,12 +2,13 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import "uno.css"; import 'uno.css'
import "./app.css"; import './app.css'
import App from "./App.svelte"; import App from './App.svelte'
import { mount } from 'svelte'
const app = new App({ const app = mount(App, {
target: document.querySelector("#app"), target: document.querySelector('#app')
}); })
export default app; export default app

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

@ -1,59 +1,59 @@
<script> <script>
import * as clipboard from "@tauri-apps/plugin-clipboard-manager"; import * as clipboard from '@tauri-apps/plugin-clipboard-manager'
import { open } from "@tauri-apps/plugin-dialog"; import { open } from '@tauri-apps/plugin-dialog'
import { arrayBufferToBase64 } from "../lib/utils"; import { arrayBufferToBase64 } from '../lib/utils'
import { readFile } from "@tauri-apps/plugin-fs"; import { readFile } from '@tauri-apps/plugin-fs'
export let onMessage; export let onMessage
export let insecureRenderHtml; export let insecureRenderHtml
let text = "clipboard message"; let text = 'clipboard message'
function writeText() { function writeText() {
clipboard clipboard
.writeText(text) .writeText(text)
.then(() => { .then(() => {
onMessage("Wrote to the clipboard"); onMessage('Wrote to the clipboard')
}) })
.catch(onMessage); .catch(onMessage)
} }
async function writeImage() { async function writeImage() {
try { try {
const res = await open({ const path = await open({
title: "Image to write to clipboard", title: 'Image to write to clipboard',
filters: [ filters: [
{ {
name: "Clipboard IMG", name: 'Clipboard IMG',
extensions: ["png", "jpg", "jpeg"], extensions: ['png', 'jpg', 'jpeg']
}, }
], ]
}); })
const bytes = await readFile(res.path); const bytes = await readFile(path)
await clipboard.writeImage(bytes); await clipboard.writeImage(bytes)
onMessage("wrote image"); onMessage('wrote image')
} catch (e) { } catch (e) {
onMessage(e); onMessage(e)
} }
} }
async function read() { async function read() {
try { try {
const image = await clipboard.readImage(); const image = await clipboard.readImage()
arrayBufferToBase64(await image.rgba(), function (base64) { arrayBufferToBase64(await image.rgba(), 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>')
}); })
return; return
} catch (_) {} } catch (_) {}
clipboard clipboard
.readText() .readText()
.then((contents) => { .then((contents) => {
onMessage(`Clipboard contents: ${contents}`); onMessage(`Clipboard contents: ${contents}`)
}) })
.catch((e) => { .catch((e) => {
onMessage(e); onMessage(e)
}); })
} }
</script> </script>
@ -65,6 +65,5 @@
/> />
<button class="btn" type="button" on:click={writeText}>Write</button> <button class="btn" type="button" on:click={writeText}>Write</button>
<button class="btn" type="button" on:click={writeImage}>Pick Image</button> <button class="btn" type="button" on:click={writeImage}>Pick Image</button>
<button class="btn" type="button" on:click={read}>Read</button> <button class="btn" type="button" on:click={read}>Read</button>
</div> </div>

@ -0,0 +1,29 @@
<script>
import {
checkPermissions,
requestPermissions,
getCurrentPosition
} from '@tauri-apps/plugin-geolocation'
export let onMessage
async function getPosition() {
let permissions = await checkPermissions()
if (
permissions.location === 'prompt' ||
permissions.location === 'prompt-with-rationale'
) {
permissions = await requestPermissions(['location'])
}
if (permissions.location === 'granted') {
getCurrentPosition().then(onMessage).catch(onMessage)
} else {
onMessage('permission denied')
}
}
</script>
<button class="btn" id="cli-matches" on:click={getPosition}>
Get Position
</button>

@ -0,0 +1,46 @@
<script>
import {
vibrate,
impactFeedback,
notificationFeedback,
selectionFeedback
} from '@tauri-apps/plugin-haptics'
export let onMessage
</script>
<div>
<button
class="btn"
on:click={() => vibrate(300).then(onMessage).catch(onMessage)}
>vibrate short</button
>
<button
class="btn"
on:click={() => vibrate(1500).then(onMessage).catch(onMessage)}
>vibrate long</button
>
<button
class="btn"
on:click={() => impactFeedback('medium').then(onMessage).catch(onMessage)}
>impact medium</button
>
<button
class="btn"
on:click={() =>
notificationFeedback('warning').then(onMessage).catch(onMessage)}
>notification warning</button
>
<button
class="btn"
on:click={() => selectionFeedback().then(onMessage).catch(onMessage)}
>selection</button
>
</div>
<br />
<p>
Depending on your device settings for haptic feedback some of the buttons may
not work.
</p>

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

@ -0,0 +1,66 @@
<script>
import * as opener from '@tauri-apps/plugin-opener'
export let onMessage
let url = ''
let urlProgram = ''
function openUrl() {
opener.openUrl(url, urlProgram ? urlProgram : undefined).catch(onMessage)
}
let path = ''
let pathProgram = ''
function openPath() {
opener
.openPath(path, pathProgram ? pathProgram : undefined)
.catch(onMessage)
}
let revealPath = ''
function revealItemInDir() {
opener.revealItemInDir(revealPath).catch(onMessage)
}
</script>
<div class="flex flex-col gap-2">
<form
class="flex flex-row gap-2 items-center"
on:submit|preventDefault={openUrl}
>
<button class="btn" type="submit">Open URL</button>
<input
class="input grow"
placeholder="Type the URL to open..."
bind:value={url}
/>
<span> with </span>
<input class="input" bind:value={urlProgram} />
</form>
<form
class="flex flex-row gap-2 items-center"
on:submit|preventDefault={openPath}
>
<button class="btn" type="submit">Open Path</button>
<input
class="input grow"
placeholder="Type the path to open..."
bind:value={path}
/>
<span> with </span>
<input class="input" bind:value={pathProgram} />
</form>
<form
class="flex flex-row gap-2 items-center"
on:submit|preventDefault={revealItemInDir}
>
<button class="btn" type="submit">Reveal</button>
<input
class="input grow"
placeholder="Type the path to reveal..."
bind:value={revealPath}
/>
</form>
</div>

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

@ -1,5 +1,5 @@
<script> <script>
import { Store } from "@tauri-apps/plugin-store"; import { LazyStore } from "@tauri-apps/plugin-store";
import { onMount } from "svelte"; import { onMount } from "svelte";
export let onMessage; export let onMessage;
@ -7,28 +7,65 @@
let key; let key;
let value; let value;
const store = new Store("cache.json"); let store = new LazyStore("cache.json");
let cache = {}; let cache = {};
onMount(async () => { async function refreshEntries() {
await store.load(); try {
const values = await store.entries(); const values = await store.entries();
for (const [key, value] of values) { cache = {};
cache[key] = value; for (const [key, value] of values) {
cache[key] = value;
}
} catch (error) {
onMessage(error);
} }
cache = cache; }
onMount(async () => {
await refreshEntries();
}); });
function write(key, value) { async function write(key, value) {
store try {
.set(key, value) if (value) {
.then(() => store.get(key)) await store.set(key, value);
.then((v) => { } else {
cache[key] = v; await store.delete(key);
}
const v = await store.get(key);
if (v === undefined) {
delete cache[key];
cache = cache; cache = cache;
}) } else {
.then(() => store.save()) cache[key] = v;
.catch(onMessage); }
} catch (error) {
onMessage(error);
}
}
async function reset() {
try {
await store.reset();
} catch (error) {
onMessage(error);
}
await refreshEntries();
}
async function close() {
try {
await store.close();
onMessage("Store is now closed, any new operations will error out");
} catch (error) {
onMessage(error);
}
}
function reopen() {
store = new LazyStore("cache.json");
onMessage("We made a new `LazyStore` instance, operations will now work");
} }
</script> </script>
@ -44,7 +81,12 @@
<input class="grow input" bind:value /> <input class="grow input" bind:value />
</div> </div>
<button class="btn" on:click={() => write(key, value)}> Write </button> <div>
<button class="btn" on:click={() => write(key, value)}>Write</button>
<button class="btn" on:click={() => reset()}>Reset</button>
<button class="btn" on:click={() => close()}>Close</button>
<button class="btn" on:click={() => reopen()}>Re-open</button>
</div>
</div> </div>
<div> <div>

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

@ -2,43 +2,43 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { defineConfig, presetIcons, presetUno, presetWebFonts } from "unocss"; import { defineConfig, presetIcons, presetUno, presetWebFonts } from 'unocss'
import extractorSvelte from "@unocss/extractor-svelte"; import extractorSvelte from '@unocss/extractor-svelte'
export default defineConfig({ export default defineConfig({
theme: { theme: {
colors: { colors: {
primary: "#FFFFFF", primary: '#FFFFFF',
primaryLighter: "#e9ecef", primaryLighter: '#e9ecef',
darkPrimary: "#1B1B1D", darkPrimary: '#1B1B1D',
darkPrimaryLighter: "#242526", darkPrimaryLighter: '#242526',
primaryText: "#1C1E21", primaryText: '#1C1E21',
darkPrimaryText: "#E3E3E3", darkPrimaryText: '#E3E3E3',
secondaryText: "#858A91", secondaryText: '#858A91',
darkSecondaryText: "#C2C5CA", darkSecondaryText: '#C2C5CA',
accent: "#3578E5", accent: '#3578E5',
accentDark: "#306cce", accentDark: '#306cce',
accentDarker: "#2d66c3", accentDarker: '#2d66c3',
accentDarkest: "#2554a0", accentDarkest: '#2554a0',
accentLight: "#538ce9", accentLight: '#538ce9',
accentLighter: "#72a1ed", accentLighter: '#72a1ed',
accentLightest: "#9abcf2", accentLightest: '#9abcf2',
accentText: "#FFFFFF", accentText: '#FFFFFF',
darkAccent: "#67d6ed", darkAccent: '#67d6ed',
darkAccentDark: "#49cee9", darkAccentDark: '#49cee9',
darkAccentDarker: "#39cae8", darkAccentDarker: '#39cae8',
darkAccentDarkest: "#19b5d5", darkAccentDarkest: '#19b5d5',
darkAccentLight: "#85def1", darkAccentLight: '#85def1',
darkAccentLighter: "#95e2f2", darkAccentLighter: '#95e2f2',
darkAccentLightest: "#c2eff8", darkAccentLightest: '#c2eff8',
darkAccentText: "#1C1E21", darkAccentText: '#1C1E21',
code: "#d6d8da", code: '#d6d8da',
codeDark: "#282a2e", codeDark: '#282a2e',
hoverOverlay: "rgba(0,0,0,.05)", hoverOverlay: 'rgba(0,0,0,.05)',
hoverOverlayDarker: "rgba(0,0,0,.1)", hoverOverlayDarker: 'rgba(0,0,0,.1)',
darkHoverOverlay: "hsla(0,0%,100%,.05)", darkHoverOverlay: 'hsla(0,0%,100%,.05)',
darkHoverOverlayDarker: "hsla(0,0%,100%,.1)", darkHoverOverlayDarker: 'hsla(0,0%,100%,.1)'
}, }
}, },
preflights: [ preflights: [
{ {
@ -54,7 +54,7 @@ export default defineConfig({
code { code {
font-size: ${theme.fontSize.xs[0]}; font-size: ${theme.fontSize.xs[0]};
font-family: ${theme.fontFamily.mono}; font-family: ${theme.fontFamily.mono};
border-radius: ${theme.borderRadius["DEFAULT"]}; border-radius: ${theme.borderRadius['DEFAULT']};
background-color: ${theme.colors.code}; background-color: ${theme.colors.code};
} }
@ -66,8 +66,8 @@ export default defineConfig({
.dark code { .dark code {
background-color: ${theme.colors.codeDark}; background-color: ${theme.colors.codeDark};
} }
`, `
}, }
], ],
shortcuts: { shortcuts: {
btn: `select-none outline-none shadow-md p-2 rd-1 text-primaryText border-none font-400 dark:font-600 btn: `select-none outline-none shadow-md p-2 rd-1 text-primaryText border-none font-400 dark:font-600
@ -81,20 +81,20 @@ export default defineConfig({
note: `decoration-none flex-inline items-center relative p-2 rd-1 note: `decoration-none flex-inline items-center relative p-2 rd-1
border-l-4 border-accent dark:border-darkAccent border-l-4 border-accent dark:border-darkAccent
bg-accent/10 dark:bg-darkAccent/10`, bg-accent/10 dark:bg-darkAccent/10`,
"note-red": 'note-red':
"note bg-red-700/10 dark:bg-red-700/10 after:bg-red-700 dark:after:bg-red-700", 'note bg-red-700/10 dark:bg-red-700/10 after:bg-red-700 dark:after:bg-red-700',
input: input:
"h-10 flex items-center outline-none border-none p-2 rd-1 shadow-md bg-primaryLighter dark:bg-darkPrimaryLighter text-primaryText dark:text-darkPrimaryText", 'h-10 flex items-center outline-none border-none p-2 rd-1 shadow-md bg-primaryLighter dark:bg-darkPrimaryLighter text-primaryText dark:text-darkPrimaryText'
}, },
presets: [ presets: [
presetUno(), presetUno(),
presetIcons(), presetIcons(),
presetWebFonts({ presetWebFonts({
fonts: { fonts: {
sans: "Rubik", sans: 'Rubik',
mono: ["Fira Code", "Fira Mono:400,700"], mono: ['Fira Code', 'Fira Mono:400,700']
}, }
}), })
], ],
extractors: [extractorSvelte], extractors: [extractorSvelte]
}); })

@ -2,12 +2,12 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { defineConfig } from "vite"; import { defineConfig } from 'vite'
import Unocss from "unocss/vite"; import Unocss from 'unocss/vite'
import { svelte } from "@sveltejs/vite-plugin-svelte"; import { svelte } from '@sveltejs/vite-plugin-svelte'
import process from "process"; import process from 'process'
const host = process.env.TAURI_DEV_HOST; const host = process.env.TAURI_DEV_HOST
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(async () => { export default defineConfig(async () => {
@ -18,24 +18,17 @@ export default defineConfig(async () => {
output: { output: {
entryFileNames: `assets/[name].js`, entryFileNames: `assets/[name].js`,
chunkFileNames: `assets/[name].js`, chunkFileNames: `assets/[name].js`,
assetFileNames: `assets/[name].[ext]`, assetFileNames: `assets/[name].[ext]`
}, }
}, }
}, },
server: { server: {
host: host || false, host: host || false,
port: 5173, port: 5173,
strictPort: true, strictPort: true,
hmr: host
? {
protocol: "ws",
host,
port: 5183,
}
: undefined,
fs: { fs: {
allow: [".", "../../tooling/api/dist"], allow: ['.', '../../tooling/api/dist']
}, }
}, }
}; }
}); })

@ -1,29 +1,30 @@
{ {
"name": "plugins-workspace", "name": "plugins-workspace",
"private": true, "private": true,
"license": "MIT or APACHE-2.0", "license": "MIT OR Apache-2.0",
"type": "module", "type": "module",
"scripts": { "scripts": {
"build": "pnpm run -r --parallel --filter !plugins-workspace --filter !\"./plugins/*/examples/**\" --filter !\"./examples/*\" build", "build": "pnpm run -r --parallel --filter !plugins-workspace --filter !\"./plugins/*/examples/**\" --filter !\"./examples/*\" build",
"lint": "eslint .", "lint": "eslint .",
"format": "prettier --write \"./**/*.{cjs,mjs,js,jsx,mts,ts,tsx,html,css,json}\" --ignore-path .prettierignore", "format": "prettier --write .",
"format-check": "prettier --check \"./**/*.{cjs,mjs,js,jsx,mts,ts,tsx,html,css,json}\" --ignore-path .prettierignore" "format:check": "prettier --check .",
"example:api:dev": "pnpm run --filter \"api\" tauri dev"
}, },
"devDependencies": { "devDependencies": {
"@eslint/js": "9.9.0", "@eslint/js": "9.18.0",
"@rollup/plugin-node-resolve": "15.2.3", "@rollup/plugin-node-resolve": "16.0.0",
"@rollup/plugin-terser": "0.4.4", "@rollup/plugin-terser": "0.4.4",
"@rollup/plugin-typescript": "11.1.6", "@rollup/plugin-typescript": "11.1.6",
"@types/eslint__js": "8.42.3", "@types/eslint__js": "8.42.3",
"covector": "^0.12.0", "covector": "^0.12.3",
"eslint": "9.9.0", "eslint": "9.18.0",
"eslint-config-prettier": "9.1.0", "eslint-config-prettier": "9.1.0",
"eslint-plugin-security": "3.0.1", "eslint-plugin-security": "3.0.1",
"prettier": "3.3.3", "prettier": "3.4.2",
"rollup": "4.21.0", "rollup": "4.30.1",
"tslib": "2.6.3", "tslib": "2.8.1",
"typescript": "5.5.4", "typescript": "5.7.3",
"typescript-eslint": "8.1.0" "typescript-eslint": "8.19.1"
}, },
"resolutions": { "resolutions": {
"semver": ">=7.5.2", "semver": ">=7.5.2",

@ -1 +0,0 @@
node_modules

@ -1,88 +0,0 @@
# Changelog
## \[2.0.0-rc.0]
- [`9887d1`](https://github.com/tauri-apps/plugins-workspace/commit/9887d14bd0e971c4c0f5c1188fc4005d3fc2e29e) Update to tauri RC.
## \[2.0.0-beta.8]
- [`99d6ac0f`](https://github.com/tauri-apps/plugins-workspace/commit/99d6ac0f9506a6a4a1aa59c728157190a7441af6) ([#1606](https://github.com/tauri-apps/plugins-workspace/pull/1606) by [@FabianLars](https://github.com/tauri-apps/plugins-workspace/../../FabianLars)) The JS packages now specify the *minimum* `@tauri-apps/api` version instead of a single exact version.
- [`6de87966`](https://github.com/tauri-apps/plugins-workspace/commit/6de87966ecc00ad9d91c25be452f1f46bd2b7e1f) ([#1597](https://github.com/tauri-apps/plugins-workspace/pull/1597) by [@Legend-Master](https://github.com/tauri-apps/plugins-workspace/../../Legend-Master)) Update to tauri beta.25.
## \[2.0.0-beta.7]
- [`22a17980`](https://github.com/tauri-apps/plugins-workspace/commit/22a17980ff4f6f8c40adb1b8f4ffc6dae2fe7e30) ([#1537](https://github.com/tauri-apps/plugins-workspace/pull/1537) by [@lucasfernog](https://github.com/tauri-apps/plugins-workspace/../../lucasfernog)) Update to tauri beta.24.
## \[2.0.0-beta.6]
- [`76daee7a`](https://github.com/tauri-apps/plugins-workspace/commit/76daee7aafece34de3092c86e531cf9eb1138989) ([#1512](https://github.com/tauri-apps/plugins-workspace/pull/1512) by [@renovate](https://github.com/tauri-apps/plugins-workspace/../../renovate)) Update to tauri beta.23.
## \[2.0.0-beta.5]
- [`9013854f`](https://github.com/tauri-apps/plugins-workspace/commit/9013854f42a49a230b9dbb9d02774765528a923f)([#1382](https://github.com/tauri-apps/plugins-workspace/pull/1382)) Update to tauri beta.22.
## \[2.0.0-beta.4]
- [`430bd6f4`](https://github.com/tauri-apps/plugins-workspace/commit/430bd6f4f379bee5d232ae6b098ae131db7f178a)([#1363](https://github.com/tauri-apps/plugins-workspace/pull/1363)) Update to tauri beta.20.
## \[2.0.0-beta.3]
- [`bd1ed590`](https://github.com/tauri-apps/plugins-workspace/commit/bd1ed5903ffcce5500310dac1e59e8c67674ef1e)([#1237](https://github.com/tauri-apps/plugins-workspace/pull/1237)) Update to tauri beta.17.
## \[2.0.0-beta.4]
- [`7e2fcc5`](https://github.com/tauri-apps/plugins-workspace/commit/7e2fcc5e74df7c3c718e40f75bfb0eafc7d69d8d)([#1146](https://github.com/tauri-apps/plugins-workspace/pull/1146)) Update dependencies to align with tauri 2.0.0-beta.14.
## \[2.0.0-beta.3]
- [`a04ea2f`](https://github.com/tauri-apps/plugins-workspace/commit/a04ea2f38294d5a3987578283badc8eec87a7752)([#1071](https://github.com/tauri-apps/plugins-workspace/pull/1071)) The global API script is now only added to the binary when the `withGlobalTauri` config is true.
## \[2.0.0-beta.2]
- [`99bea25`](https://github.com/tauri-apps/plugins-workspace/commit/99bea2559c2c0648c2519c50a18cd124dacef57b)([#1005](https://github.com/tauri-apps/plugins-workspace/pull/1005)) Update to tauri beta.8.
## \[2.0.0-beta.1]
- [`569defb`](https://github.com/tauri-apps/plugins-workspace/commit/569defbe9492e38938554bb7bdc1be9151456d21) Update to tauri beta.4.
## \[2.0.0-beta.0]
- [`d198c01`](https://github.com/tauri-apps/plugins-workspace/commit/d198c014863ee260cb0de88a14b7fc4356ef7474)([#862](https://github.com/tauri-apps/plugins-workspace/pull/862)) Update to tauri beta.
## \[2.0.0-alpha.5]
- [`387c2f9`](https://github.com/tauri-apps/plugins-workspace/commit/387c2f9e0ce4c75c07ffa3fd76391a25b58f5daf)([#802](https://github.com/tauri-apps/plugins-workspace/pull/802)) Update to @tauri-apps/api v2.0.0-alpha.13.
## \[2.0.0-alpha.4]
- [`387c2f9`](https://github.com/tauri-apps/plugins-workspace/commit/387c2f9e0ce4c75c07ffa3fd76391a25b58f5daf)([#802](https://github.com/tauri-apps/plugins-workspace/pull/802)) Update to @tauri-apps/api v2.0.0-alpha.12.
## \[2.0.0-alpha.3]
- [`e438e0a`](https://github.com/tauri-apps/plugins-workspace/commit/e438e0a62d4b430a5159f05f13ecd397dd891a0d)([#676](https://github.com/tauri-apps/plugins-workspace/pull/676)) Update to @tauri-apps/api v2.0.0-alpha.11.
## \[2.0.0-alpha.2]
- [`5c13736`](https://github.com/tauri-apps/plugins-workspace/commit/5c137365c60790e8d4037d449e8237aa3fffdab0)([#673](https://github.com/tauri-apps/plugins-workspace/pull/673)) Update to @tauri-apps/api v2.0.0-alpha.9.
## \[2.0.0-alpha.2]
- [`4e2cef9`](https://github.com/tauri-apps/plugins-workspace/commit/4e2cef9b702bbbb9cf4ee17de50791cb21f1b2a4)([#593](https://github.com/tauri-apps/plugins-workspace/pull/593)) Update to alpha.12.
## \[2.0.0-alpha.1]
- [`d74fc0a`](https://github.com/tauri-apps/plugins-workspace/commit/d74fc0a097996e90a37be8f57d50b7d1f6ca616f)([#555](https://github.com/tauri-apps/plugins-workspace/pull/555)) Update to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
te to alpha.11.
## \[2.0.0-alpha.0]
- [`717ae67`](https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
ae67\`]\(https://github.com/tauri-apps/plugins-workspace/commit/717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
\-workspace/pull/371)) First v2 alpha release!
717ae670978feb4492fac1f295998b93f2b9347f)([#371](https://github.com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!
com/tauri-apps/plugins-workspace/pull/371)) First v2 alpha release!

@ -1,41 +0,0 @@
[package]
name = "tauri-plugin-authenticator"
version = "2.0.0-rc.0"
description = "Use hardware security-keys in your Tauri App."
authors = { workspace = true }
license = { workspace = true }
edition = { workspace = true }
rust-version = { workspace = true }
repository = { workspace = true }
links = "tauri-plugin-authenticator"
[package.metadata.docs.rs]
rustc-args = [ "--cfg", "docsrs" ]
rustdoc-args = [ "--cfg", "docsrs" ]
[build-dependencies]
tauri-plugin = { workspace = true, features = [ "build" ] }
[dependencies]
serde = { workspace = true }
serde_json = { workspace = true }
tauri = { workspace = true }
log = { workspace = true }
thiserror = { workspace = true }
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
authenticator = "0.3.1"
once_cell = "1"
sha2 = "0.10"
base64 = "0.22"
chrono = "0.4"
bytes = "1"
byteorder = "1"
openssl = "0.10"
[target."cfg(target_os = \"windows\")".dependencies]
winapi-util = "=0.1.6"
[dev-dependencies]
rand = "0.8"
rusty-fork = "0.3"

@ -1,143 +0,0 @@
![plugin-authenticator](https://github.com/tauri-apps/plugins-workspace/raw/v2/plugins/authenticator/banner.png)
Use hardware security-keys in your Tauri App.
- Supported platforms: Windows, Linux, FreeBSD, NetBSD, OpenBSD, and macOS.
## Install
_This plugin requires a Rust version of at least **1.75**_
There are three general methods of installation that we can recommend.
1. Use crates.io and npm (easiest and requires you to trust that our publishing pipeline worked)
2. Pull sources directly from Github using git tags / revision hashes (most secure)
3. Git submodule install this repo in your tauri project and then use the file protocol to ingest the source (most secure, but inconvenient to use)
Install the authenticator plugin by adding the following lines to your `Cargo.toml` file:
`src-tauri/Cargo.toml`
```toml
# you can add the dependencies on the `[dependencies]` section if you do not target mobile
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
tauri-plugin-authenticator = "2.0.0-rc"
# alternatively with Git:
tauri-plugin-authenticator = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
> Note: Since most JavaScript package managers are unable to install packages from git monorepos we provide read-only mirrors of each plugin. This makes installation option 2 more ergonomic to use.
```sh
pnpm add @tauri-apps/plugin-authenticator
# or
npm add @tauri-apps/plugin-authenticator
# or
yarn add @tauri-apps/plugin-authenticator
```
Alternatively with Git:
```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or
npm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or
yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
```
## Usage
First, you need to register the authenticator plugin with Tauri:
`src-tauri/src/main.rs`
```rust
fn main() {
tauri::Builder::default()
.setup(|app| {
#[cfg(desktop)]
app.handle().plugin(tauri_plugin_authenticator::init())?;
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
```
Afterwards, all the plugin's APIs are available through the JavaScript guest bindings:
```javascript
import { Authenticator } from "@tauri-apps/plugin-authenticator";
const auth = new Authenticator();
auth.init(); // initialize transports
// generate a 32-bytes long random challenge
const arr = new Uint32Array(32);
window.crypto.getRandomValues(arr);
const b64 = btoa(String.fromCharCode.apply(null, arr));
// web-safe base64
const challenge = b64.replace(/\+/g, "-").replace(/\//g, "_");
const domain = "https://tauri.app";
// attempt to register with the security key
const json = await auth.register(challenge, domain);
const registerResult = JSON.parse(json);
// verify the registration was successful
const r2 = await auth.verifyRegistration(
challenge,
app,
registerResult.registerData,
registerResult.clientData,
);
const j2 = JSON.parse(r2);
// sign some data
const json = await auth.sign(challenge, app, keyHandle);
const signData = JSON.parse(json);
// verify the signature again
const counter = await auth.verifySignature(
challenge,
app,
signData.signData,
clientData,
keyHandle,
pubkey,
);
if (counter && counter > 0) {
console.log("SUCCESS!");
}
```
## Contributing
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
## Partners
<table>
<tbody>
<tr>
<td align="center" valign="middle">
<a href="https://crabnebula.dev" target="_blank">
<img src="https://github.com/tauri-apps/plugins-workspace/raw/v2/.github/sponsors/crabnebula.svg" alt="CrabNebula" width="283">
</a>
</td>
</tr>
</tbody>
</table>
For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
## License
Code: (c) 2015 - Present - The Tauri Programme within The Commons Conservancy.
MIT or MIT/Apache 2.0 where applicable.

@ -1 +0,0 @@
if("__TAURI__"in window){var __TAURI_PLUGIN_AUTHENTICATOR__=function(t){"use strict";async function i(t,i={},a){return window.__TAURI_INTERNALS__.invoke(t,i,a)}"function"==typeof SuppressedError&&SuppressedError;return t.Authenticator=class{async init(){await i("plugin:authenticator|init_auth")}async register(t,a){return await i("plugin:authenticator|register",{timeout:1e4,challenge:t,application:a})}async verifyRegistration(t,a,e,n){return await i("plugin:authenticator|verify_registration",{challenge:t,application:a,registerData:e,clientData:n})}async sign(t,a,e){return await i("plugin:authenticator|sign",{timeout:1e4,challenge:t,application:a,keyHandle:e})}async verifySignature(t,a,e,n,r,u){return await i("plugin:authenticator|verify_signature",{challenge:t,application:a,signData:e,clientData:n,keyHandle:r,pubkey:u})}},t}({});Object.defineProperty(window.__TAURI__,"authenticator",{value:__TAURI_PLUGIN_AUTHENTICATOR__})}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

@ -1,17 +0,0 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
const COMMANDS: &[&str] = &[
"init_auth",
"register",
"verify_registration",
"sign",
"verify_signature",
];
fn main() {
tauri_plugin::Builder::new(COMMANDS)
.global_api_script_path("./api-iife.js")
.build();
}

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

Loading…
Cancel
Save