mirror of
https://github.com/tauri-apps/plugins-workspace.git
synced 2026-06-16 14:30:06 +02:00
Compare commits
143 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a71a0192b8 | |||
| e7d9efee37 | |||
| dd8bc4ab39 | |||
| 8d6045421a | |||
| c77cbe936d | |||
| 11048fd997 | |||
| f595684ba8 | |||
| d472eebad2 | |||
| c27699ffab | |||
| 68d77f999c | |||
| 1712f27b77 | |||
| 8dd371814a | |||
| 5c3b2f7511 | |||
| 227bf5424a | |||
| c25b7537e3 | |||
| 9e24e52164 | |||
| 444a16ca73 | |||
| cff0cdeaa8 | |||
| 57c1db41a3 | |||
| 6630e5db75 | |||
| 662c61826b | |||
| 44df7726ae | |||
| b4535af927 | |||
| 77b81af36c | |||
| 9b20f28d74 | |||
| 1e56d86b51 | |||
| 07650ca94b | |||
| d68d5cce60 | |||
| faab5f6cee | |||
| 4ecc649839 | |||
| 9f27e6e441 | |||
| 3f0917bd50 | |||
| 9048f80a4e | |||
| ac7390973b | |||
| d5f5d78830 | |||
| 1f799ae25e | |||
| fa32d1afa9 | |||
| f41d3e5e77 | |||
| 9b96996b5a | |||
| 9af4c3727c | |||
| 3d279094d4 | |||
| 6c7a4c0984 | |||
| 1c17161f2a | |||
| 6111c7f3da | |||
| 746067bb70 | |||
| 0623903f12 | |||
| 043de033b0 | |||
| 7432a399db | |||
| 305c5793ae | |||
| 4a39b74d5c | |||
| dc5a14b6ad | |||
| 2b65e0a149 | |||
| beb9095f11 | |||
| 418294b1a3 | |||
| 3febb72f28 | |||
| 90fecadb86 | |||
| 63834d9b63 | |||
| 8654caa26e | |||
| 473991371d | |||
| e98e8eac3d | |||
| 44d8f60e0d | |||
| b04bde3461 | |||
| 0190f68f1d | |||
| 5b85dd22c7 | |||
| 76832e60bf | |||
| 5b814f56e6 | |||
| 6647e6ea90 | |||
| 83148da959 | |||
| e8d7e765e7 | |||
| 76bcecf5b2 | |||
| d49aa664e9 | |||
| bd0d88243a | |||
| f001df870f | |||
| 72a6e3ba68 | |||
| 7e58dc8502 | |||
| ac495b9fb4 | |||
| dacde1629d | |||
| 700549ab02 | |||
| 811b1ec12d | |||
| 174c5e52e3 | |||
| 37d057df61 | |||
| cdb77c4b65 | |||
| e47dca954f | |||
| 94f62d2503 | |||
| ee0d314bb5 | |||
| ae8a581f9a | |||
| 67bff4559d | |||
| d272bde2bb | |||
| 919616d7d3 | |||
| b60b46a0b8 | |||
| 6d8f517148 | |||
| 949c59f8a5 | |||
| b99844706e | |||
| 92514cca47 | |||
| 81fb450c39 | |||
| c3a6dab24c | |||
| 0863f800b8 | |||
| 600ad30756 | |||
| 51f20b438e | |||
| 4fd6b58070 | |||
| c8c6d56d1b | |||
| 2ed0fd716c | |||
| 8286b06198 | |||
| 180ec441aa | |||
| 07f3a89df0 | |||
| c009cb383f | |||
| 00915af7e7 | |||
| c499238892 | |||
| ac6f08f193 | |||
| 84d8a21e55 | |||
| 280f99c5f3 | |||
| 8c10a1b0a7 | |||
| b6ffbe33da | |||
| 2f2da76aa8 | |||
| 9dba680114 | |||
| 2365c46534 | |||
| 01ede23b34 | |||
| a2503b795d | |||
| 65e6870195 | |||
| ec74b2d69a | |||
| 6845cefc82 | |||
| 2a8e168149 | |||
| efcc3df3fe | |||
| 9e440d27ae | |||
| 395ff65547 | |||
| ad3028646c | |||
| 0d0ed7b907 | |||
| 92233ea64a | |||
| 36b7296746 | |||
| d9b2331237 | |||
| 8916544034 | |||
| 3d4697b34a | |||
| 9174b808dc | |||
| a305ad3ddb | |||
| 7b9d7a1d88 | |||
| c4d2c8c693 | |||
| be2a90b7e2 | |||
| 417c85a2dd | |||
| 617cf38069 | |||
| 6ad221ed36 | |||
| 0984fc8374 | |||
| 523bcdc528 | |||
| ea63b40224 |
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold-js": patch
|
||||
---
|
||||
|
||||
Change the argument name of the `Stronghold.remove` from `location` to `recordPath` to match the Stronghold command argument
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"stronghold": patch
|
||||
---
|
||||
|
||||
Added `Builder::with_argon2`.
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
"positioner": patch
|
||||
---
|
||||
|
||||
`TrayLeft`, `TrayRight` and `TrayCenter` will now position the window according to the tray position relative to the monitor dimensions to prevent windows being displayed partially off-screen.
|
||||
@@ -45,6 +45,8 @@ jobs:
|
||||
- name: build
|
||||
run: cargo build --workspace --exclude 'tauri-plugin-sql' --all-targets --all-features
|
||||
|
||||
- uses: dtolnay/rust-toolchain@1.65.0
|
||||
|
||||
- name: build sql:sqlite
|
||||
run: cargo build --package 'tauri-plugin-sql' --all-targets --features sqlite
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ https.get(url, options, (response) => {
|
||||
console.log(versions.length ? versions[0].num : "0.0.0");
|
||||
} else if (kind === "npm") {
|
||||
const versions = Object.keys(data.versions).filter((v) =>
|
||||
v.startsWith(target)
|
||||
v.startsWith(target),
|
||||
);
|
||||
console.log(versions[versions.length - 1] || "0.0.0");
|
||||
}
|
||||
|
||||
Generated
+1247
-1026
File diff suppressed because it is too large
Load Diff
+27
-16
@@ -10,23 +10,34 @@
|
||||
"format-check": "prettier --check ."
|
||||
},
|
||||
"devDependencies": {
|
||||
"@rollup/plugin-node-resolve": "^15.0.2",
|
||||
"@rollup/plugin-terser": "^0.4.1",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.58.0",
|
||||
"@typescript-eslint/parser": "^5.58.0",
|
||||
"eslint": "^8.38.0",
|
||||
"eslint-config-prettier": "^8.8.0",
|
||||
"eslint-config-standard-with-typescript": "^35.0.0",
|
||||
"eslint-plugin-import": "^2.27.5",
|
||||
"eslint-plugin-n": "^16.0.0",
|
||||
"eslint-plugin-promise": "^6.1.1",
|
||||
"eslint-plugin-security": "^1.7.1",
|
||||
"prettier": "^2.8.7",
|
||||
"rollup": "^3.20.4",
|
||||
"typescript": "^5.0.4"
|
||||
"@rollup/plugin-node-resolve": "15.2.3",
|
||||
"@rollup/plugin-terser": "0.4.4",
|
||||
"@rollup/plugin-typescript": "11.1.5",
|
||||
"@typescript-eslint/eslint-plugin": "6.9.1",
|
||||
"@typescript-eslint/parser": "6.9.1",
|
||||
"eslint": "8.52.0",
|
||||
"eslint-config-prettier": "9.0.0",
|
||||
"eslint-config-standard-with-typescript": "39.1.1",
|
||||
"eslint-plugin-import": "2.29.0",
|
||||
"eslint-plugin-n": "16.2.0",
|
||||
"eslint-plugin-promise": "6.1.1",
|
||||
"eslint-plugin-security": "1.7.1",
|
||||
"prettier": "3.0.3",
|
||||
"rollup": "4.2.0",
|
||||
"typescript": "5.2.2"
|
||||
},
|
||||
"resolutions": {
|
||||
"semver": ">=7.5.2",
|
||||
"optionator": ">=0.9.3"
|
||||
},
|
||||
"engines": {
|
||||
"pnpm": ">=7.33.0"
|
||||
"pnpm": ">=7.33.1"
|
||||
},
|
||||
"pnpm": {
|
||||
"auditConfig": {
|
||||
"ignoreCves": [
|
||||
"CVE-2023-46115"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ _This plugin requires a Rust version of at least **1.64**_
|
||||
|
||||
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)
|
||||
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 file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
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 Core plugin by adding the following to your `Cargo.toml` file:
|
||||
Install the authenticator plugin by adding the following lines to your `Cargo.toml` file:
|
||||
|
||||
`src-tauri/Cargo.toml`
|
||||
|
||||
@@ -28,16 +28,16 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-authenticator
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-authenticator#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-authenticator
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-authenticator#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-authenticator
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to register the core plugin with Tauri:
|
||||
First, you need to register the authenticator plugin with Tauri:
|
||||
|
||||
`src-tauri/src/main.rs`
|
||||
|
||||
@@ -50,7 +50,7 @@ fn main() {
|
||||
}
|
||||
```
|
||||
|
||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
Afterwards, all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
|
||||
```javascript
|
||||
import { Authenticator } from "tauri-plugin-authenticator-api";
|
||||
@@ -71,12 +71,12 @@ const domain = "https://tauri.app";
|
||||
const json = await auth.register(challenge, domain);
|
||||
const registerResult = JSON.parse(json);
|
||||
|
||||
// verify te registration was successfull
|
||||
// verify the registration was successful
|
||||
const r2 = await auth.verifyRegistration(
|
||||
challenge,
|
||||
app,
|
||||
registerResult.registerData,
|
||||
registerResult.clientData
|
||||
registerResult.clientData,
|
||||
);
|
||||
const j2 = JSON.parse(r2);
|
||||
|
||||
@@ -91,7 +91,7 @@ const counter = await auth.verifySignature(
|
||||
signData.signData,
|
||||
clientData,
|
||||
keyHandle,
|
||||
pubkey
|
||||
pubkey,
|
||||
);
|
||||
|
||||
if (counter && counter > 0) {
|
||||
|
||||
@@ -17,7 +17,7 @@ export class Authenticator {
|
||||
challenge: string,
|
||||
application: string,
|
||||
registerData: string,
|
||||
clientData: string
|
||||
clientData: string,
|
||||
): Promise<string> {
|
||||
return await invoke("plugin:authenticator|verify_registration", {
|
||||
challenge,
|
||||
@@ -30,7 +30,7 @@ export class Authenticator {
|
||||
async sign(
|
||||
challenge: string,
|
||||
application: string,
|
||||
keyHandle: string
|
||||
keyHandle: string,
|
||||
): Promise<string> {
|
||||
return await invoke("plugin:authenticator|sign", {
|
||||
timeout: 10000,
|
||||
@@ -46,7 +46,7 @@ export class Authenticator {
|
||||
signData: string,
|
||||
clientData: string,
|
||||
keyHandle: string,
|
||||
pubkey: string
|
||||
pubkey: string,
|
||||
): Promise<number> {
|
||||
return await invoke("plugin:authenticator|verify_signature", {
|
||||
challenge,
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -15,4 +15,4 @@ serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
auto-launch = "0.4"
|
||||
auto-launch = "0.5"
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-autostart
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-autostart#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-autostart
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-autostart#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-autostart
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-autostart#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-fs-extra
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-fs-extra#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-fs-extra
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-fs-extra#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-fs-extra
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-fs-extra#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -16,4 +16,4 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
notify = { version = "6" , features = ["serde"] }
|
||||
notify-debouncer-mini = { version = "0.3" , features = ["serde"] }
|
||||
notify-debouncer-mini = { version = "0.4" , features = ["serde"] }
|
||||
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-fs-watch
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-fs-watch#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-fs-watch
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-fs-watch#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-fs-watch
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-fs-watch#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -57,17 +57,17 @@ import { watch, watchImmediate } from "tauri-plugin-fs-watch-api";
|
||||
const stopWatching = await watch(
|
||||
"/path/to/something",
|
||||
(event) => {
|
||||
const { type, payload } = event;
|
||||
const { kind, path } = event;
|
||||
},
|
||||
{ recursive: true }
|
||||
{ recursive: true },
|
||||
);
|
||||
|
||||
const stopRawWatcher = await watchImmediate(
|
||||
["/path/a", "/path/b"],
|
||||
(event) => {
|
||||
const { path, operation, cookie } = event;
|
||||
const { type, paths, attrs } = event;
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ async function unwatch(id: number): Promise<void> {
|
||||
export async function watch(
|
||||
paths: string | string[],
|
||||
cb: (event: DebouncedEvent) => void,
|
||||
options: DebouncedWatchOptions = {}
|
||||
options: DebouncedWatchOptions = {},
|
||||
): Promise<UnlistenFn> {
|
||||
const opts = {
|
||||
recursive: false,
|
||||
@@ -71,7 +71,7 @@ export async function watch(
|
||||
`watcher://debounced-event/${id}`,
|
||||
(event) => {
|
||||
cb(event.payload);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
@@ -83,7 +83,7 @@ export async function watch(
|
||||
export async function watchImmediate(
|
||||
paths: string | string[],
|
||||
cb: (event: RawEvent) => void,
|
||||
options: WatchOptions = {}
|
||||
options: WatchOptions = {},
|
||||
): Promise<UnlistenFn> {
|
||||
const opts = {
|
||||
recursive: false,
|
||||
@@ -109,7 +109,7 @@ export async function watchImmediate(
|
||||
`watcher://raw-event/${id}`,
|
||||
(event) => {
|
||||
cb(event.payload);
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return () => {
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -91,7 +91,7 @@ async fn watch<R: Runtime>(
|
||||
|
||||
let watcher = if let Some(delay) = options.delay_ms {
|
||||
let (tx, rx) = channel();
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), None, tx)?;
|
||||
let mut debouncer = new_debouncer(Duration::from_millis(delay), tx)?;
|
||||
let watcher = debouncer.watcher();
|
||||
for path in &paths {
|
||||
watcher.watch(path, mode)?;
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-log
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-log#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-log
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-log#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-log
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-log#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -43,7 +43,7 @@ enum LogLevel {
|
||||
async function log(
|
||||
level: LogLevel,
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
const traces = new Error().stack?.split("\n").map((line) => line.split("@"));
|
||||
|
||||
@@ -86,7 +86,7 @@ async function log(
|
||||
*/
|
||||
export async function error(
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
await log(LogLevel.Error, message, options);
|
||||
}
|
||||
@@ -108,7 +108,7 @@ export async function error(
|
||||
*/
|
||||
export async function warn(
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
await log(LogLevel.Warn, message, options);
|
||||
}
|
||||
@@ -130,7 +130,7 @@ export async function warn(
|
||||
*/
|
||||
export async function info(
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
await log(LogLevel.Info, message, options);
|
||||
}
|
||||
@@ -152,7 +152,7 @@ export async function info(
|
||||
*/
|
||||
export async function debug(
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
await log(LogLevel.Debug, message, options);
|
||||
}
|
||||
@@ -174,7 +174,7 @@ export async function debug(
|
||||
*/
|
||||
export async function trace(
|
||||
message: string,
|
||||
options?: LogOptions
|
||||
options?: LogOptions,
|
||||
): Promise<void> {
|
||||
await log(LogLevel.Trace, message, options);
|
||||
}
|
||||
@@ -193,7 +193,7 @@ export async function attachConsole(): Promise<UnlistenFn> {
|
||||
// TODO: Investigate security/detect-unsafe-regex
|
||||
// eslint-disable-next-line no-control-regex, security/detect-unsafe-regex
|
||||
/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
|
||||
""
|
||||
"",
|
||||
);
|
||||
|
||||
switch (payload.level) {
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
+35
-7
@@ -118,7 +118,7 @@ pub enum LogTarget {
|
||||
///
|
||||
/// The plugin will ensure the directory exists before writing logs.
|
||||
Folder(PathBuf),
|
||||
/// Write logs to the OS specififc logs directory.
|
||||
/// Write logs to the OS specific logs directory.
|
||||
///
|
||||
/// ### Platform-specific
|
||||
///
|
||||
@@ -167,6 +167,7 @@ pub struct Builder {
|
||||
timezone_strategy: TimezoneStrategy,
|
||||
max_file_size: u128,
|
||||
targets: Vec<LogTarget>,
|
||||
log_name: Option<String>,
|
||||
}
|
||||
|
||||
impl Default for Builder {
|
||||
@@ -189,6 +190,7 @@ impl Default for Builder {
|
||||
timezone_strategy: DEFAULT_TIMEZONE_STRATEGY,
|
||||
max_file_size: DEFAULT_MAX_FILE_SIZE,
|
||||
targets: DEFAULT_LOG_TARGETS.into(),
|
||||
log_name: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -262,6 +264,29 @@ impl Builder {
|
||||
self
|
||||
}
|
||||
|
||||
/// Writes logs to the given file. Default: <app_name>.log)
|
||||
///
|
||||
/// Note: This does not modify the directory logs go into. For that refer to `LogTarget::Folder`.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use tauri_plugin_log::Builder;
|
||||
/// let name = "custom-name";
|
||||
/// let builder = Builder::default()
|
||||
/// .targets([
|
||||
/// LogTarget::LogDir
|
||||
/// ])
|
||||
/// .log_name(name)
|
||||
/// .build()
|
||||
/// ); // Outputs content to custom-name.log
|
||||
///
|
||||
/// ```
|
||||
pub fn log_name<S: Into<String>>(mut self, log_name: S) -> Self {
|
||||
self.log_name = Some(log_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
#[cfg(feature = "colored")]
|
||||
pub fn with_colors(self, colors: fern::colors::ColoredLevelConfig) -> Self {
|
||||
let format =
|
||||
@@ -284,7 +309,10 @@ impl Builder {
|
||||
plugin::Builder::new("log")
|
||||
.invoke_handler(tauri::generate_handler![log])
|
||||
.setup(move |app_handle| {
|
||||
let app_name = &app_handle.package_info().name;
|
||||
let log_name = self
|
||||
.log_name
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| &app_handle.package_info().name);
|
||||
|
||||
// setup targets
|
||||
for target in &self.targets {
|
||||
@@ -298,7 +326,7 @@ impl Builder {
|
||||
|
||||
fern::log_file(get_log_file_path(
|
||||
&path,
|
||||
app_name,
|
||||
log_name,
|
||||
&self.rotation_strategy,
|
||||
&self.timezone_strategy,
|
||||
self.max_file_size,
|
||||
@@ -313,7 +341,7 @@ impl Builder {
|
||||
|
||||
fern::log_file(get_log_file_path(
|
||||
&path,
|
||||
app_name,
|
||||
log_name,
|
||||
&self.rotation_strategy,
|
||||
&self.timezone_strategy,
|
||||
self.max_file_size,
|
||||
@@ -347,12 +375,12 @@ impl Builder {
|
||||
|
||||
fn get_log_file_path(
|
||||
dir: &impl AsRef<Path>,
|
||||
app_name: &str,
|
||||
log_name: &str,
|
||||
rotation_strategy: &RotationStrategy,
|
||||
timezone_strategy: &TimezoneStrategy,
|
||||
max_file_size: u128,
|
||||
) -> plugin::Result<PathBuf> {
|
||||
let path = dir.as_ref().join(format!("{app_name}.log"));
|
||||
let path = dir.as_ref().join(format!("{log_name}.log"));
|
||||
|
||||
if path.exists() {
|
||||
let log_size = File::open(&path)?.metadata()?.len() as u128;
|
||||
@@ -361,7 +389,7 @@ fn get_log_file_path(
|
||||
RotationStrategy::KeepAll => {
|
||||
let to = dir.as_ref().join(format!(
|
||||
"{}_{}.log",
|
||||
app_name,
|
||||
log_name,
|
||||
timezone_strategy
|
||||
.get_now()
|
||||
.format(
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -1,5 +1,15 @@
|
||||
# Changelog
|
||||
|
||||
## \[0.1.3]
|
||||
|
||||
- Split up fs and asset scopes. **This will reset the asset protocol scope once!**
|
||||
- [ad30286](https://github.com/tauri-apps/plugins-workspace/commit/ad3028646c96ed213a2f483823ffdc3c17b5fc1e) fix(persisted-scope): separately save asset protocol patterns ([#459](https://github.com/tauri-apps/plugins-workspace/pull/459)) on 2023-07-10
|
||||
|
||||
## \[0.1.2]
|
||||
|
||||
- Fix usage of directory patterns by removing glob asterisks at the end before allowing/forbidding them. This was causing them to be escaped, and so undesirable paths were allowed/forbidden while polluting the `.persisted_scope` file.
|
||||
- [9174b80](https://github.com/tauri-apps/plugins-workspace/commit/9174b808dc37154999c119fcc3f31258a9c5a3fb) \[persisted scope] fix: handle recursive directory correctly ([#455](https://github.com/tauri-apps/plugins-workspace/pull/455)) on 2023-06-29
|
||||
|
||||
## \[0.1.1]
|
||||
|
||||
- The MSRV was raised to 1.64!
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "tauri-plugin-persisted-scope"
|
||||
version = "0.1.1"
|
||||
version = "0.1.3"
|
||||
description = "Save filesystem and asset scopes and restore them when the app is reopened."
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
@@ -15,7 +15,7 @@ serde_json.workspace = true
|
||||
tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
aho-corasick = "1.0"
|
||||
aho-corasick = "1.1"
|
||||
bincode = "1"
|
||||
|
||||
[features]
|
||||
|
||||
@@ -6,7 +6,7 @@ use aho_corasick::AhoCorasick;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::{
|
||||
plugin::{Builder, TauriPlugin},
|
||||
AppHandle, FsScopeEvent, Manager, Runtime,
|
||||
FsScope, FsScopeEvent, Manager, Runtime,
|
||||
};
|
||||
|
||||
use std::{
|
||||
@@ -15,7 +15,10 @@ use std::{
|
||||
path::Path,
|
||||
};
|
||||
|
||||
// Using 2 separate files so that we don't have to think about write conflicts and not break backwards compat.
|
||||
const SCOPE_STATE_FILENAME: &str = ".persisted-scope";
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
const ASSET_SCOPE_STATE_FILENAME: &str = ".persisted-scope-asset";
|
||||
|
||||
// Most of these patterns are just added to try to fix broken files in the wild.
|
||||
// After a while we can hopefully reduce it to something like [r"[?]", r"[*]", r"\\?\\\?\"]
|
||||
@@ -42,6 +45,14 @@ enum Error {
|
||||
Bincode(#[from] Box<bincode::ErrorKind>),
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, Eq, PartialEq, Hash)]
|
||||
enum TargetType {
|
||||
#[default]
|
||||
File,
|
||||
Directory,
|
||||
RecursiveDirectory,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize)]
|
||||
struct Scope {
|
||||
allowed_paths: Vec<String>,
|
||||
@@ -58,16 +69,74 @@ fn fix_pattern(ac: &AhoCorasick, s: &str) -> String {
|
||||
s
|
||||
}
|
||||
|
||||
fn save_scopes<R: Runtime>(app: &AppHandle<R>, app_dir: &Path, scope_state_path: &Path) {
|
||||
let fs_scope = app.fs_scope();
|
||||
const RESURSIVE_DIRECTORY_SUFFIX: &str = "**";
|
||||
const DIRECTORY_SUFFIX: &str = "*";
|
||||
|
||||
fn detect_scope_type(scope_state_path: &str) -> TargetType {
|
||||
if scope_state_path.ends_with(RESURSIVE_DIRECTORY_SUFFIX) {
|
||||
TargetType::RecursiveDirectory
|
||||
} else if scope_state_path.ends_with(DIRECTORY_SUFFIX) {
|
||||
TargetType::Directory
|
||||
} else {
|
||||
TargetType::File
|
||||
}
|
||||
}
|
||||
|
||||
fn fix_directory(path_str: &str) -> &Path {
|
||||
let mut path = Path::new(path_str);
|
||||
|
||||
if path.ends_with(DIRECTORY_SUFFIX) || path.ends_with(RESURSIVE_DIRECTORY_SUFFIX) {
|
||||
path = match path.parent() {
|
||||
Some(value) => value,
|
||||
None => return path,
|
||||
};
|
||||
}
|
||||
|
||||
path
|
||||
}
|
||||
|
||||
fn allow_path(scope: &FsScope, path: &str) {
|
||||
let target_type = detect_scope_type(path);
|
||||
|
||||
match target_type {
|
||||
TargetType::File => {
|
||||
let _ = scope.allow_file(path);
|
||||
}
|
||||
TargetType::Directory => {
|
||||
// We remove the '*' at the end of it, else it will be escaped by the pattern.
|
||||
let _ = scope.allow_directory(fix_directory(path), false);
|
||||
}
|
||||
TargetType::RecursiveDirectory => {
|
||||
// We remove the '**' at the end of it, else it will be escaped by the pattern.
|
||||
let _ = scope.allow_directory(fix_directory(path), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn forbid_path(scope: &FsScope, path: &str) {
|
||||
let target_type = detect_scope_type(path);
|
||||
|
||||
match target_type {
|
||||
TargetType::File => {
|
||||
let _ = scope.forbid_file(path);
|
||||
}
|
||||
TargetType::Directory => {
|
||||
let _ = scope.forbid_directory(fix_directory(path), false);
|
||||
}
|
||||
TargetType::RecursiveDirectory => {
|
||||
let _ = scope.forbid_directory(fix_directory(path), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn save_scopes(scope: &FsScope, app_dir: &Path, scope_state_path: &Path) {
|
||||
let scope = Scope {
|
||||
allowed_paths: fs_scope
|
||||
allowed_paths: scope
|
||||
.allowed_patterns()
|
||||
.into_iter()
|
||||
.map(|p| p.to_string())
|
||||
.collect(),
|
||||
forbidden_patterns: fs_scope
|
||||
forbidden_patterns: scope
|
||||
.forbidden_patterns()
|
||||
.into_iter()
|
||||
.map(|p| p.to_string())
|
||||
@@ -93,46 +162,74 @@ pub fn init<R: Runtime>() -> TauriPlugin<R> {
|
||||
let app_dir = app.path_resolver().app_data_dir();
|
||||
|
||||
if let Some(app_dir) = app_dir {
|
||||
let scope_state_path = app_dir.join(SCOPE_STATE_FILENAME);
|
||||
|
||||
let _ = fs_scope.forbid_file(&scope_state_path);
|
||||
let fs_scope_state_path = app_dir.join(SCOPE_STATE_FILENAME);
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let _ = asset_protocol_scope.forbid_file(&scope_state_path);
|
||||
let asset_scope_state_path = app_dir.join(ASSET_SCOPE_STATE_FILENAME);
|
||||
|
||||
let _ = fs_scope.forbid_file(&fs_scope_state_path);
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let _ = asset_protocol_scope.forbid_file(&asset_scope_state_path);
|
||||
|
||||
// We're trying to fix broken .persisted-scope files seamlessly, so we'll be running this on the values read on the saved file.
|
||||
// We will still save some semi-broken values because the scope events are quite spammy and we don't want to reduce runtime performance any further.
|
||||
let ac = AhoCorasick::new(PATTERNS).unwrap(/* This should be impossible to fail since we're using a small static input */);
|
||||
|
||||
if scope_state_path.exists() {
|
||||
let scope: Scope = tauri::api::file::read_binary(&scope_state_path)
|
||||
if fs_scope_state_path.exists() {
|
||||
let scope: Scope = tauri::api::file::read_binary(&fs_scope_state_path)
|
||||
.map_err(Error::from)
|
||||
.and_then(|scope| bincode::deserialize(&scope).map_err(Into::into))
|
||||
.unwrap_or_default();
|
||||
|
||||
for allowed in &scope.allowed_paths {
|
||||
let allowed = fix_pattern(&ac, allowed);
|
||||
|
||||
let _ = fs_scope.allow_file(&allowed);
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let _ = asset_protocol_scope.allow_file(&allowed);
|
||||
allow_path(&fs_scope, &allowed);
|
||||
}
|
||||
for forbidden in &scope.forbidden_patterns {
|
||||
let forbidden = fix_pattern(&ac, forbidden);
|
||||
|
||||
let _ = fs_scope.forbid_file(&forbidden);
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let _ = asset_protocol_scope.forbid_file(&forbidden);
|
||||
forbid_path(&fs_scope, &forbidden);
|
||||
}
|
||||
|
||||
// Manually save the fixed scopes to disk once.
|
||||
// This is needed to fix broken .peristed-scope files in case the app doesn't update the scope itself.
|
||||
save_scopes(&app, &app_dir, &scope_state_path);
|
||||
save_scopes(&fs_scope, &app_dir, &fs_scope_state_path);
|
||||
}
|
||||
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
if asset_scope_state_path.exists() {
|
||||
let scope: Scope = tauri::api::file::read_binary(&asset_scope_state_path)
|
||||
.map_err(Error::from)
|
||||
.and_then(|scope| bincode::deserialize(&scope).map_err(Into::into))
|
||||
.unwrap_or_default();
|
||||
|
||||
for allowed in &scope.allowed_paths {
|
||||
let allowed = fix_pattern(&ac, allowed);
|
||||
allow_path(&asset_protocol_scope, &allowed);
|
||||
}
|
||||
for forbidden in &scope.forbidden_patterns {
|
||||
let forbidden = fix_pattern(&ac, forbidden);
|
||||
forbid_path(&asset_protocol_scope, &forbidden);
|
||||
}
|
||||
|
||||
// Manually save the fixed scopes to disk once.
|
||||
save_scopes(&asset_protocol_scope, &app_dir, &asset_scope_state_path);
|
||||
}
|
||||
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
let app_dir_ = app_dir.clone();
|
||||
let fs_scope_ = fs_scope.clone();
|
||||
fs_scope.listen(move |event| {
|
||||
if let FsScopeEvent::PathAllowed(_) = event {
|
||||
save_scopes(&app, &app_dir, &scope_state_path);
|
||||
save_scopes(&fs_scope_, &app_dir, &fs_scope_state_path);
|
||||
}
|
||||
});
|
||||
#[cfg(feature = "protocol-asset")]
|
||||
{
|
||||
let asset_protocol_scope_ = asset_protocol_scope.clone();
|
||||
asset_protocol_scope.listen(move |event| {
|
||||
if let FsScopeEvent::PathAllowed(_) = event {
|
||||
save_scopes(&asset_protocol_scope_, &app_dir_, &asset_scope_state_path);
|
||||
}
|
||||
});}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
|
||||
@@ -40,11 +40,11 @@ yarn add tauri-plugin-positioner-api
|
||||
Or through git:
|
||||
|
||||
```sh
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-positioner
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-positioner#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-positioner
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-positioner#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-positioner
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-positioner#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -107,13 +107,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
},
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayLeft => {
|
||||
if let Some((tray_x, tray_y)) = tray_position {
|
||||
PhysicalPosition {
|
||||
x: tray_x,
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
if let (Some((tray_x, tray_y)), Some((_, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x: tray_x, y }
|
||||
} else {
|
||||
panic!("tray position not set");
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
@@ -129,11 +136,20 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayRight => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition {
|
||||
x: tray_x + tray_width,
|
||||
y: tray_y - window_size.height,
|
||||
y,
|
||||
}
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
@@ -153,12 +169,19 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
#[cfg(feature = "system-tray")]
|
||||
TrayCenter => {
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _))) = (tray_position, tray_size)
|
||||
if let (Some((tray_x, tray_y)), Some((tray_width, _tray_height))) =
|
||||
(tray_position, tray_size)
|
||||
{
|
||||
PhysicalPosition {
|
||||
x: tray_x + (tray_width / 2) - (window_size.width / 2),
|
||||
y: tray_y - window_size.height,
|
||||
}
|
||||
let x = tray_x + tray_width / 2 - window_size.width / 2;
|
||||
let y = tray_y - window_size.height;
|
||||
// Choose y value based on the target OS
|
||||
#[cfg(target_os = "windows")]
|
||||
let y = if y < 0 { tray_y + _tray_height } else { y };
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
let y = if y < 0 { tray_y } else { y };
|
||||
|
||||
PhysicalPosition { x, y }
|
||||
} else {
|
||||
panic!("Tray position not set");
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -9,6 +9,6 @@
|
||||
"author": "",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@tauri-apps/cli": "^1.2.3"
|
||||
"@tauri-apps/cli": "1.5.5"
|
||||
}
|
||||
}
|
||||
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@tauri-apps/cli': ^1.0.0
|
||||
|
||||
dependencies:
|
||||
'@tauri-apps/cli': 1.0.2
|
||||
|
||||
packages:
|
||||
|
||||
/@tauri-apps/cli-darwin-arm64/1.0.2:
|
||||
resolution: {integrity: sha512-Ahd951yoYon1+WLNBg6xsx6Bb7+GJt7WwC1FllHZ2/iLCbrtWCS2qfeLS0L4ngBqCuWyL35JC/M2LIr9mcUzrg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-darwin-x64/1.0.2:
|
||||
resolution: {integrity: sha512-8wo+SN1zWoXFQVa/iyEt3Cs0vNMjxDXqVe3Srm4UNpgKboFN5mIgbugwqvM+aJKnEZAH8h8n+ZJUHzc4wtPGHA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm-gnueabihf/1.0.2:
|
||||
resolution: {integrity: sha512-PGQghMn0adt9PTnyi2K2o/CLG3tWbOyZvwQjam5cfQbK757WmMgPErC1VqsxiQc+PItWYvqoE9gjANiFc2MpAQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm64-gnu/1.0.2:
|
||||
resolution: {integrity: sha512-Uc+XNlWelrnRh7DYrdxBi8Oam9JAQM1GzgEwjupF6Pv7BwlODN7s0HImGPQOKrEkqzpfmYw7KpfgWiiEjS5/3Q==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-arm64-musl/1.0.2:
|
||||
resolution: {integrity: sha512-lVwCG1QzQs2zWP32H4+Dw8NKgJ6hBox2X+bmawGfV9Ce+K4P84bnqfNgpdaSAncjeiTjrO+g7yT9gJFQCOrjlQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-x64-gnu/1.0.2:
|
||||
resolution: {integrity: sha512-G2XmGxvufW9sgGhA3rx+HehcifVTUo8zyISd8DpvGwtpp6Z4WakbivzKFyGiNnnok0nvj/WUrLgBxtUbfdSY+A==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-linux-x64-musl/1.0.2:
|
||||
resolution: {integrity: sha512-/eX536p+KXSmkFuINGeU6EQmYiQEXj6JXbmetmJmkXN0297HbtH3rS3wlyVDCnobRzh1hMeOJEnV+XA20GghMA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-win32-ia32-msvc/1.0.2:
|
||||
resolution: {integrity: sha512-ZvnaKkCABqUbyUKlNk4RdxKyfOte30D5BxN1pj6iZNeKAwXEuTcgP6iPzOovdeaDirkIjcWCEZymwtZDXN4Rvg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli-win32-x64-msvc/1.0.2:
|
||||
resolution: {integrity: sha512-uMcQyQQD7nyxps34HyYBYUYzFwH26lP58/qdT/GZWvBL1Sv2rqkQXuxHT7xtp4g7nTs0fGRWOtfcnvYIr/1wDw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: false
|
||||
optional: true
|
||||
|
||||
/@tauri-apps/cli/1.0.2:
|
||||
resolution: {integrity: sha512-OJdQJVwtKnTAuv2a9JQlOd0gHbbGsXwT+N6M6YQiXZ3/5WdlXey1zhnD78GXwZsf8Cz0R7QIGTBECO4ur4fnKg==}
|
||||
engines: {node: '>= 10'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
'@tauri-apps/cli-darwin-arm64': 1.0.2
|
||||
'@tauri-apps/cli-darwin-x64': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm-gnueabihf': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm64-gnu': 1.0.2
|
||||
'@tauri-apps/cli-linux-arm64-musl': 1.0.2
|
||||
'@tauri-apps/cli-linux-x64-gnu': 1.0.2
|
||||
'@tauri-apps/cli-linux-x64-musl': 1.0.2
|
||||
'@tauri-apps/cli-win32-ia32-msvc': 1.0.2
|
||||
'@tauri-apps/cli-win32-x64-msvc': 1.0.2
|
||||
dev: false
|
||||
@@ -5,7 +5,8 @@ description = "Interface with SQL databases."
|
||||
authors.workspace = true
|
||||
license.workspace = true
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
#rust-version.workspace = true
|
||||
rust-version = "1.65"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
@@ -16,11 +17,11 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
futures-core = "0.3"
|
||||
sqlx = { version = "0.6", features = ["runtime-tokio-rustls", "json", "time"] }
|
||||
sqlx = { version = "0.7", features = ["json", "time"] }
|
||||
time = "0.3"
|
||||
tokio = { version = "1", features = ["sync"] }
|
||||
|
||||
[features]
|
||||
sqlite = ["sqlx/sqlite"]
|
||||
mysql = ["sqlx/mysql"]
|
||||
postgres = ["sqlx/postgres"]
|
||||
sqlite = ["sqlx/sqlite", "sqlx/runtime-tokio"]
|
||||
mysql = ["sqlx/mysql", "sqlx/runtime-tokio-rustls"]
|
||||
postgres = ["sqlx/postgres", "sqlx/runtime-tokio-rustls"]
|
||||
|
||||
+35
-4
@@ -4,7 +4,7 @@ Interface with SQL databases through [sqlx](https://github.com/launchbadge/sqlx)
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.64**_
|
||||
_This plugin requires a Rust version of at least **1.65**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
@@ -28,11 +28,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-sql
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-sql
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-sql#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-sql
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-sql#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -65,6 +65,37 @@ const db = await Database.load("postgres://postgres:password@localhost/test");
|
||||
await db.execute("INSERT INTO ...");
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
We use sqlx as our underlying library, adopting their query syntax:
|
||||
|
||||
- sqlite and postgres use the "$#" syntax when substituting query data
|
||||
- mysql uses "?" when substituting query data
|
||||
|
||||
```javascript
|
||||
// INSERT and UPDATE examples for sqlite and postgres
|
||||
const result = await db.execute(
|
||||
"INSERT into todos (id, title, status) VALUES ($1, $2, $3)",
|
||||
[todos.id, todos.title, todos.status],
|
||||
);
|
||||
|
||||
const result = await db.execute(
|
||||
"UPDATE todos SET title = $1, completed = $2 WHERE id = $3",
|
||||
[todos.title, todos.status, todos.id],
|
||||
);
|
||||
|
||||
// INSERT and UPDATE examples for mysql
|
||||
const result = await db.execute(
|
||||
"INSERT into todos (id, title, status) VALUES (?, ?, ?)",
|
||||
[todos.id, todos.title, todos.status],
|
||||
);
|
||||
|
||||
const result = await db.execute(
|
||||
"UPDATE todos SET title = ?, completed = ? WHERE id = ?",
|
||||
[todos.title, todos.status, todos.id],
|
||||
);
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
|
||||
|
||||
@@ -76,10 +76,29 @@ export default class Database {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // for sqlite & postgres
|
||||
* // INSERT example
|
||||
* const result = await db.execute(
|
||||
* "INSERT into todos (id, title, status) VALUES ($1, $2, $3)",
|
||||
* [ todos.id, todos.title, todos.status ]
|
||||
* );
|
||||
* // UPDATE example
|
||||
* const result = await db.execute(
|
||||
* "UPDATE todos SET title = $1, completed = $2 WHERE id = $3",
|
||||
* [ todos.title, todos.status, todos.id ]
|
||||
* );
|
||||
*
|
||||
* // for mysql
|
||||
* // INSERT example
|
||||
* const result = await db.execute(
|
||||
* "INSERT into todos (id, title, status) VALUES (?, ?, ?)",
|
||||
* [ todos.id, todos.title, todos.status ]
|
||||
* );
|
||||
* // UPDATE example
|
||||
* const result = await db.execute(
|
||||
* "UPDATE todos SET title = ?, completed = ? WHERE id = ?",
|
||||
* [ todos.title, todos.status, todos.id ]
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
async execute(query: string, bindValues?: unknown[]): Promise<QueryResult> {
|
||||
@@ -89,15 +108,13 @@ export default class Database {
|
||||
db: this.path,
|
||||
query,
|
||||
values: bindValues ?? [],
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
return {
|
||||
lastInsertId,
|
||||
rowsAffected,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* **select**
|
||||
*
|
||||
@@ -105,9 +122,15 @@ export default class Database {
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* // for sqlite & postgres
|
||||
* const result = await db.select(
|
||||
* "SELECT * from todos WHERE id = $1", id
|
||||
* );
|
||||
*
|
||||
* // for mysql
|
||||
* const result = await db.select(
|
||||
* "SELECT * from todos WHERE id = ?", id
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
async select<T>(query: string, bindValues?: unknown[]): Promise<T> {
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -17,7 +17,14 @@ pub(crate) fn to_json(v: MySqlValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT" | "DOUBLE" => {
|
||||
"FLOAT" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"DOUBLE" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
|
||||
@@ -17,14 +17,35 @@ pub(crate) fn to_json(v: PgValueRef) -> Result<JsonValue, Error> {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT4" | "FLOAT8" => {
|
||||
"FLOAT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f32>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"FLOAT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<f64>() {
|
||||
JsonValue::from(v)
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT2" | "INT4" | "INT8" => {
|
||||
"INT2" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i16>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT4" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i32>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
JsonValue::Null
|
||||
}
|
||||
}
|
||||
"INT8" => {
|
||||
if let Ok(v) = ValueRef::to_owned(&v).try_decode::<i64>() {
|
||||
JsonValue::Number(v.into())
|
||||
} else {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-store
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-store#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-store
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-store#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-store
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-store#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -177,7 +177,7 @@ export class Store {
|
||||
*/
|
||||
async onKeyChange<T>(
|
||||
key: string,
|
||||
cb: (value: T | null) => void
|
||||
cb: (value: T | null) => void,
|
||||
): Promise<UnlistenFn> {
|
||||
return await listen<ChangePayload<T>>("store://change", (event) => {
|
||||
if (event.payload.path === this.path && event.payload.key === key) {
|
||||
@@ -192,7 +192,7 @@ export class Store {
|
||||
* @returns A promise resolving to a function to unlisten to the event.
|
||||
*/
|
||||
async onChange<T>(
|
||||
cb: (key: string, value: T | null) => void
|
||||
cb: (key: string, value: T | null) => void,
|
||||
): Promise<UnlistenFn> {
|
||||
return await listen<ChangePayload<T>>("store://change", (event) => {
|
||||
if (event.payload.path === this.path) {
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -16,10 +16,19 @@ tauri.workspace = true
|
||||
log.workspace = true
|
||||
thiserror.workspace = true
|
||||
iota_stronghold = "1"
|
||||
iota-crypto = "0.20"
|
||||
iota-crypto = "0.23"
|
||||
hex = "0.4"
|
||||
zeroize = { version = "1", features = ["zeroize_derive"] }
|
||||
|
||||
# kdf dependencies
|
||||
rust-argon2 = { version = "1", optional = true }
|
||||
rand_chacha = { version = "0.3.1", optional = true }
|
||||
rand_core = { version = "0.6.4", features = ["getrandom"], optional = true }
|
||||
|
||||
[dev-dependencies]
|
||||
rand = "0.8"
|
||||
rusty-fork = "0.3"
|
||||
rusty-fork = "0.3"
|
||||
|
||||
[features]
|
||||
default = ["kdf"]
|
||||
kdf = ["dep:rust-argon2", "dep:rand_chacha", "dep:rand_core"]
|
||||
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-stronghold
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-stronghold#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-stronghold
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-stronghold#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-stronghold
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-stronghold#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -23,7 +23,7 @@ export type StoreKey =
|
||||
| ArrayBuffer;
|
||||
|
||||
function toBytesDto(
|
||||
v: ClientPath | VaultPath | RecordPath | StoreKey
|
||||
v: ClientPath | VaultPath | RecordPath | StoreKey,
|
||||
): string | number[] {
|
||||
if (typeof v === "string") {
|
||||
return v;
|
||||
@@ -125,7 +125,7 @@ class ProcedureExecutor {
|
||||
*/
|
||||
async generateSLIP10Seed(
|
||||
outputLocation: Location,
|
||||
sizeBytes?: number
|
||||
sizeBytes?: number,
|
||||
): Promise<Uint8Array> {
|
||||
return await invoke<number[]>("plugin:stronghold|execute_procedure", {
|
||||
...this.procedureArgs,
|
||||
@@ -152,7 +152,7 @@ class ProcedureExecutor {
|
||||
chain: number[],
|
||||
source: "Seed" | "Key",
|
||||
sourceLocation: Location,
|
||||
outputLocation: Location
|
||||
outputLocation: Location,
|
||||
): Promise<Uint8Array> {
|
||||
return await invoke<number[]>("plugin:stronghold|execute_procedure", {
|
||||
...this.procedureArgs,
|
||||
@@ -181,7 +181,7 @@ class ProcedureExecutor {
|
||||
async recoverBIP39(
|
||||
mnemonic: string,
|
||||
outputLocation: Location,
|
||||
passphrase?: string
|
||||
passphrase?: string,
|
||||
): Promise<Uint8Array> {
|
||||
return await invoke<number[]>("plugin:stronghold|execute_procedure", {
|
||||
...this.procedureArgs,
|
||||
@@ -205,7 +205,7 @@ class ProcedureExecutor {
|
||||
*/
|
||||
async generateBIP39(
|
||||
outputLocation: Location,
|
||||
passphrase?: string
|
||||
passphrase?: string,
|
||||
): Promise<Uint8Array> {
|
||||
return await invoke<number[]>("plugin:stronghold|execute_procedure", {
|
||||
...this.procedureArgs,
|
||||
@@ -245,7 +245,7 @@ class ProcedureExecutor {
|
||||
*/
|
||||
async signEd25519(
|
||||
privateKeyLocation: Location,
|
||||
msg: string
|
||||
msg: string,
|
||||
): Promise<Uint8Array> {
|
||||
return await invoke<number[]>("plugin:stronghold|execute_procedure", {
|
||||
...this.procedureArgs,
|
||||
@@ -293,18 +293,24 @@ export class Store {
|
||||
this.client = client;
|
||||
}
|
||||
|
||||
async get(key: StoreKey): Promise<Uint8Array> {
|
||||
async get(key: StoreKey): Promise<Uint8Array | null> {
|
||||
return await invoke<number[]>("plugin:stronghold|get_store_record", {
|
||||
snapshotPath: this.path,
|
||||
client: this.client,
|
||||
key: toBytesDto(key),
|
||||
}).then((v) => Uint8Array.from(v));
|
||||
}).then((v) => {
|
||||
if (v) {
|
||||
return Uint8Array.from(v);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async insert(
|
||||
key: StoreKey,
|
||||
value: number[],
|
||||
lifetime?: Duration
|
||||
lifetime?: Duration,
|
||||
): Promise<void> {
|
||||
return await invoke("plugin:stronghold|save_store_record", {
|
||||
snapshotPath: this.path,
|
||||
@@ -322,7 +328,7 @@ export class Store {
|
||||
snapshotPath: this.path,
|
||||
client: this.client,
|
||||
key: toBytesDto(key),
|
||||
}
|
||||
},
|
||||
).then((v) => (v != null ? Uint8Array.from(v) : null));
|
||||
}
|
||||
}
|
||||
@@ -378,7 +384,7 @@ export class Vault extends ProcedureExecutor {
|
||||
snapshotPath: this.path,
|
||||
client: this.client,
|
||||
vault: this.name,
|
||||
location,
|
||||
recordPath: location.payload.record,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
use rand_chacha::ChaCha20Rng;
|
||||
use rand_core::{RngCore, SeedableRng};
|
||||
use std::path::Path;
|
||||
|
||||
/// NOTE: Hash supplied to Stronghold must be 32bits long.
|
||||
/// This is a current limitation of Stronghold.
|
||||
const HASH_LENGTH: usize = 32;
|
||||
|
||||
pub struct KeyDerivation {}
|
||||
|
||||
impl KeyDerivation {
|
||||
/// Will create a key from [`password`] and a generated salt.
|
||||
/// Salt will be generated to file [`salt_path`] or taken from it
|
||||
/// if file already exists
|
||||
pub fn argon2(password: &str, salt_path: &Path) -> Vec<u8> {
|
||||
let mut salt = [0u8; HASH_LENGTH];
|
||||
create_or_get_salt(&mut salt, salt_path);
|
||||
|
||||
argon2::hash_raw(password.as_bytes(), &salt, &Default::default())
|
||||
.expect("Failed to generate hash for password")
|
||||
}
|
||||
}
|
||||
|
||||
fn create_or_get_salt(salt: &mut [u8], salt_path: &Path) {
|
||||
if salt_path.is_file() {
|
||||
// Get existing salt
|
||||
let tmp = std::fs::read(salt_path).unwrap();
|
||||
salt.clone_from_slice(&tmp);
|
||||
} else {
|
||||
// Generate new salt
|
||||
let mut gen = ChaCha20Rng::from_entropy();
|
||||
gen.fill_bytes(salt);
|
||||
std::fs::write(salt_path, salt).expect("Failed to write salt for Stronghold")
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,9 @@ use tauri::{
|
||||
};
|
||||
use zeroize::Zeroize;
|
||||
|
||||
#[cfg(feature = "kdf")]
|
||||
pub mod kdf;
|
||||
|
||||
pub mod stronghold;
|
||||
|
||||
type PasswordHashFn = dyn Fn(&str) -> Vec<u8> + Send + Sync;
|
||||
@@ -394,26 +397,70 @@ fn get_client(
|
||||
}
|
||||
}
|
||||
|
||||
enum PasswordHashFunctionKind {
|
||||
#[cfg(feature = "kdf")]
|
||||
Argon2(PathBuf),
|
||||
Custom(Box<PasswordHashFn>),
|
||||
}
|
||||
|
||||
pub struct Builder {
|
||||
password_hash_function: Box<PasswordHashFn>,
|
||||
password_hash_function: PasswordHashFunctionKind,
|
||||
}
|
||||
|
||||
impl Builder {
|
||||
pub fn new<F: Fn(&str) -> Vec<u8> + Send + Sync + 'static>(password_hash_function: F) -> Self {
|
||||
Self {
|
||||
password_hash_function: Box::new(password_hash_function),
|
||||
password_hash_function: PasswordHashFunctionKind::Custom(Box::new(
|
||||
password_hash_function,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Initializes [`Self`] with argon2 as password hash function.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// tauri::Builder::default()
|
||||
/// .setup(|app| {
|
||||
/// let salt_path = app
|
||||
/// .path_resolver()
|
||||
/// .app_local_data_dir()
|
||||
/// .expect("could not resolve app local data path")
|
||||
/// .join("salt.txt");
|
||||
/// app.handle().plugin(tauri_plugin_stronghold::Builder::with_argon2(&salt_path).build())?;
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// ```
|
||||
#[cfg(feature = "kdf")]
|
||||
pub fn with_argon2(salt_path: &std::path::Path) -> Self {
|
||||
Self {
|
||||
password_hash_function: PasswordHashFunctionKind::Argon2(salt_path.to_owned()),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn build<R: Runtime>(self) -> TauriPlugin<R> {
|
||||
let password_hash_function = self.password_hash_function;
|
||||
|
||||
PluginBuilder::new("stronghold")
|
||||
.setup(move |app| {
|
||||
app.manage(StrongholdCollection::default());
|
||||
app.manage(PasswordHashFunction(password_hash_function));
|
||||
Ok(())
|
||||
})
|
||||
let plugin_builder = PluginBuilder::new("stronghold").setup(move |app| {
|
||||
app.manage(StrongholdCollection::default());
|
||||
app.manage(PasswordHashFunction(match password_hash_function {
|
||||
#[cfg(feature = "kdf")]
|
||||
PasswordHashFunctionKind::Argon2(path) => {
|
||||
Box::new(move |p| kdf::KeyDerivation::argon2(p, &path))
|
||||
}
|
||||
PasswordHashFunctionKind::Custom(f) => f,
|
||||
}));
|
||||
Ok(())
|
||||
});
|
||||
|
||||
Builder::invoke_stronghold_handlers_and_build(plugin_builder)
|
||||
}
|
||||
|
||||
fn invoke_stronghold_handlers_and_build<R: Runtime>(
|
||||
builder: PluginBuilder<R>,
|
||||
) -> TauriPlugin<R> {
|
||||
builder
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
initialize,
|
||||
destroy,
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -27,11 +27,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-upload
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-upload#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-upload
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-upload#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-upload
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-upload#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -58,7 +58,7 @@ upload(
|
||||
"https://example.com/file-upload",
|
||||
"./path/to/my/file.txt",
|
||||
(progress, total) => console.log(`Uploaded ${progress} of ${total} bytes`), // a callback that will be called with the upload progress
|
||||
{ "Content-Type": "text/plain" } // optional headers to send with the request
|
||||
{ "Content-Type": "text/plain" }, // optional headers to send with the request
|
||||
);
|
||||
```
|
||||
|
||||
@@ -69,7 +69,7 @@ download(
|
||||
"https://example.com/file-download-link",
|
||||
"./path/to/save/my/file.txt",
|
||||
(progress, total) => console.log(`Downloaded ${progress} of ${total} bytes`), // a callback that will be called with the download progress
|
||||
{ "Content-Type": "text/plain" } // optional headers to send with the request
|
||||
{ "Content-Type": "text/plain" }, // optional headers to send with the request
|
||||
);
|
||||
```
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ async function upload(
|
||||
url: string,
|
||||
filePath: string,
|
||||
progressHandler?: ProgressHandler,
|
||||
headers?: Map<string, string>
|
||||
headers?: Map<string, string>,
|
||||
): Promise<void> {
|
||||
const ids = new Uint32Array(1);
|
||||
window.crypto.getRandomValues(ids);
|
||||
@@ -59,7 +59,7 @@ async function download(
|
||||
url: string,
|
||||
filePath: string,
|
||||
progressHandler?: ProgressHandler,
|
||||
headers?: Map<string, string>
|
||||
headers?: Map<string, string>,
|
||||
): Promise<void> {
|
||||
const ids = new Uint32Array(1);
|
||||
window.crypto.getRandomValues(ids);
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
+37
-10
@@ -9,7 +9,10 @@ use tauri::{
|
||||
plugin::{Builder as PluginBuilder, TauriPlugin},
|
||||
Runtime, Window,
|
||||
};
|
||||
use tokio::{fs::File, io::AsyncWriteExt};
|
||||
use tokio::{
|
||||
fs::File,
|
||||
io::{AsyncWriteExt, BufWriter},
|
||||
};
|
||||
use tokio_util::codec::{BytesCodec, FramedRead};
|
||||
|
||||
use read_progress_stream::ReadProgressStream;
|
||||
@@ -64,20 +67,44 @@ async fn download<R: Runtime>(
|
||||
let response = request.send().await?;
|
||||
let total = response.content_length().unwrap_or(0);
|
||||
|
||||
let mut file = File::create(file_path).await?;
|
||||
let mut file = BufWriter::new(File::create(file_path).await?);
|
||||
let mut stream = response.bytes_stream();
|
||||
|
||||
let mut i = 0;
|
||||
let mut temp_progress = 0;
|
||||
|
||||
while let Some(chunk) = stream.try_next().await? {
|
||||
i = i + 1;
|
||||
file.write_all(&chunk).await?;
|
||||
let _ = window.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: chunk.len() as u64,
|
||||
total,
|
||||
},
|
||||
);
|
||||
temp_progress = temp_progress + chunk.len();
|
||||
if i >= 10 {
|
||||
window
|
||||
.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: temp_progress as u64,
|
||||
total,
|
||||
},
|
||||
)
|
||||
.unwrap(); // TODO: remove the unwrap again.
|
||||
i = 0;
|
||||
temp_progress = 0;
|
||||
}
|
||||
}
|
||||
if temp_progress != 0 {
|
||||
window
|
||||
.emit(
|
||||
"download://progress",
|
||||
ProgressPayload {
|
||||
id,
|
||||
progress: temp_progress as u64,
|
||||
total,
|
||||
},
|
||||
)
|
||||
.unwrap(); // TODO: remove the unwrap again.
|
||||
}
|
||||
file.flush().await?;
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -18,4 +18,4 @@ thiserror.workspace = true
|
||||
rand = "0.8"
|
||||
futures-util = "0.3"
|
||||
tokio = { version = "1", features = ["net", "sync"] }
|
||||
tokio-tungstenite = { version = "0.19", features = ["native-tls"] }
|
||||
tokio-tungstenite = { version = "0.20", features = ["native-tls"] }
|
||||
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-websocket
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-websocket#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-websocket
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-websocket#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-websocket
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-websocket#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
@@ -51,7 +51,7 @@ fn main() {
|
||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
|
||||
```javascript
|
||||
import { WebSocket } from "tauri-plugin-websocket-api";
|
||||
import WebSocket from "tauri-plugin-websocket-api";
|
||||
|
||||
const ws = await WebSocket.connect("wss://example.com");
|
||||
|
||||
|
||||
@@ -11,14 +11,14 @@
|
||||
"tauri": "tauri"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-auto": "^2.0.0",
|
||||
"@sveltejs/kit": "^1.15.5",
|
||||
"@tauri-apps/cli": "^1.2.3",
|
||||
"svelte": "^3.58.0",
|
||||
"svelte-check": "^3.2.0",
|
||||
"tslib": "^2.5.0",
|
||||
"typescript": "^5.0.4",
|
||||
"vite": "^4.2.1"
|
||||
"@sveltejs/adapter-auto": "2.1.0",
|
||||
"@sveltejs/kit": "1.27.2",
|
||||
"@tauri-apps/cli": "1.5.5",
|
||||
"svelte": "4.2.2",
|
||||
"svelte-check": "3.5.2",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "5.2.2",
|
||||
"vite": "4.5.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"tauri-plugin-websocket-api": "link:../../"
|
||||
|
||||
+4
-4
@@ -2774,9 +2774,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tokio-tungstenite"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c"
|
||||
checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2"
|
||||
dependencies = [
|
||||
"futures-util",
|
||||
"log",
|
||||
@@ -2806,9 +2806,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tungstenite"
|
||||
version = "0.19.0"
|
||||
version = "0.20.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67"
|
||||
checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649"
|
||||
dependencies = [
|
||||
"byteorder",
|
||||
"bytes",
|
||||
|
||||
@@ -13,7 +13,7 @@ tauri = { version = "1", features = [] }
|
||||
tokio = { version = "1", features = ["net"] }
|
||||
futures-util = "0.3"
|
||||
tauri-plugin-websocket = { path = "../../../" }
|
||||
tokio-tungstenite = "0.19"
|
||||
tokio-tungstenite = "0.20"
|
||||
|
||||
[build-dependencies]
|
||||
tauri-build = { version = "1", features = [] }
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<!DOCTYPE html>
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
import { invoke, transformCallback } from "@tauri-apps/api/tauri";
|
||||
|
||||
export interface ConnectionConfig {
|
||||
writeBufferSize?: number;
|
||||
maxWriteBufferSize?: number;
|
||||
maxMessageSize?: number;
|
||||
maxFrameSize?: number;
|
||||
acceptUnmaskedFrames?: boolean;
|
||||
headers?: HeadersInit;
|
||||
}
|
||||
|
||||
export interface MessageKind<T, D> {
|
||||
type: T;
|
||||
data: D;
|
||||
@@ -26,16 +35,23 @@ export default class WebSocket {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
static async connect(url: string, options?: unknown): Promise<WebSocket> {
|
||||
static async connect(
|
||||
url: string,
|
||||
config?: ConnectionConfig,
|
||||
): Promise<WebSocket> {
|
||||
const listeners: Array<(arg: Message) => void> = [];
|
||||
const handler = (message: Message): void => {
|
||||
listeners.forEach((l) => l(message));
|
||||
};
|
||||
|
||||
if (config?.headers) {
|
||||
config.headers = Array.from(new Headers(config.headers).entries());
|
||||
}
|
||||
|
||||
return await invoke<number>("plugin:websocket|connect", {
|
||||
url,
|
||||
callbackFunction: transformCallback(handler),
|
||||
options,
|
||||
config,
|
||||
}).then((id) => new WebSocket(id, listeners));
|
||||
}
|
||||
|
||||
@@ -53,7 +69,7 @@ export default class WebSocket {
|
||||
m = { type: "Binary", data: message };
|
||||
} else {
|
||||
throw new Error(
|
||||
"invalid `message` type, expected a `{ type: string, data: any }` object, a string or a numeric array"
|
||||
"invalid `message` type, expected a `{ type: string, data: any }` object, a string or a numeric array",
|
||||
);
|
||||
}
|
||||
return await invoke("plugin:websocket|send", {
|
||||
|
||||
@@ -24,9 +24,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -16,6 +16,9 @@ use tokio_tungstenite::{
|
||||
};
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::str::FromStr;
|
||||
use tauri::http::header::{HeaderName, HeaderValue};
|
||||
use tokio_tungstenite::tungstenite::client::IntoClientRequest;
|
||||
|
||||
type Id = u32;
|
||||
type WebSocket = WebSocketStream<MaybeTlsStream<TcpStream>>;
|
||||
@@ -28,6 +31,10 @@ enum Error {
|
||||
Websocket(#[from] tokio_tungstenite::tungstenite::Error),
|
||||
#[error("connection not found for the given id: {0}")]
|
||||
ConnectionNotFound(Id),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderValue(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderValue),
|
||||
#[error(transparent)]
|
||||
InvalidHeaderName(#[from] tokio_tungstenite::tungstenite::http::header::InvalidHeaderName),
|
||||
}
|
||||
|
||||
impl Serialize for Error {
|
||||
@@ -42,20 +49,29 @@ impl Serialize for Error {
|
||||
#[derive(Default)]
|
||||
struct ConnectionManager(Mutex<HashMap<Id, WebSocketWriter>>);
|
||||
|
||||
#[derive(Default, Deserialize)]
|
||||
#[derive(Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct ConnectionConfig {
|
||||
pub max_send_queue: Option<usize>,
|
||||
pub write_buffer_size: Option<usize>,
|
||||
pub max_write_buffer_size: Option<usize>,
|
||||
pub max_message_size: Option<usize>,
|
||||
pub max_frame_size: Option<usize>,
|
||||
#[serde(default)]
|
||||
pub accept_unmasked_frames: bool,
|
||||
pub headers: Option<Vec<(String, String)>>,
|
||||
}
|
||||
|
||||
impl From<ConnectionConfig> for WebSocketConfig {
|
||||
fn from(config: ConnectionConfig) -> Self {
|
||||
// Disabling the warning on max_send_queue which we don't use anymore since it was deprecated.
|
||||
#[allow(deprecated)]
|
||||
Self {
|
||||
max_send_queue: config.max_send_queue,
|
||||
max_send_queue: None,
|
||||
write_buffer_size: config.write_buffer_size.unwrap_or(128 * 1024),
|
||||
max_write_buffer_size: config.max_write_buffer_size.unwrap_or(usize::MAX),
|
||||
// This may be harmful since if it's not provided from js we're overwriting the default value with None, meaning no size limit.
|
||||
max_message_size: config.max_message_size,
|
||||
// This may be harmful since if it's not provided from js we're overwriting the default value with None, meaning no size limit.
|
||||
max_frame_size: config.max_frame_size,
|
||||
accept_unmasked_frames: config.accept_unmasked_frames,
|
||||
}
|
||||
@@ -86,7 +102,17 @@ async fn connect<R: Runtime>(
|
||||
config: Option<ConnectionConfig>,
|
||||
) -> Result<Id> {
|
||||
let id = rand::random();
|
||||
let (ws_stream, _) = connect_async_with_config(url, config.map(Into::into), false).await?;
|
||||
let mut request = url.into_client_request()?;
|
||||
|
||||
if let Some(headers) = config.as_ref().and_then(|c| c.headers.as_ref()) {
|
||||
for (k, v) in headers {
|
||||
let header_name = HeaderName::from_str(k.as_str())?;
|
||||
let header_value = HeaderValue::from_str(v.as_str())?;
|
||||
request.headers_mut().insert(header_name, header_value);
|
||||
}
|
||||
}
|
||||
|
||||
let (ws_stream, _) = connect_async_with_config(request, config.map(Into::into), false).await?;
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
let (write, read) = ws_stream.split();
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
@@ -26,11 +26,11 @@ You can install the JavaScript Guest bindings using your preferred JavaScript pa
|
||||
> 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 https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
pnpm add https://github.com/tauri-apps/tauri-plugin-window-state#v1
|
||||
# or
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
npm add https://github.com/tauri-apps/tauri-plugin-window-state#v1
|
||||
# or
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-window-state
|
||||
yarn add https://github.com/tauri-apps/tauri-plugin-window-state#v1
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
@@ -14,22 +14,25 @@ export enum StateFlags {
|
||||
/**
|
||||
* Save the state of all open windows to disk.
|
||||
*/
|
||||
async function saveWindowState(flags: StateFlags) {
|
||||
invoke("plugin:window-state|save_window_state", { flags });
|
||||
async function saveWindowState(flags: StateFlags): Promise<void> {
|
||||
return invoke("plugin:window-state|save_window_state", { flags });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state for the specified window from disk.
|
||||
*/
|
||||
async function restoreState(label: WindowLabel, flags: StateFlags) {
|
||||
invoke("plugin:window-state|restore_state", { label, flags });
|
||||
async function restoreState(
|
||||
label: WindowLabel,
|
||||
flags: StateFlags,
|
||||
): Promise<void> {
|
||||
return invoke("plugin:window-state|restore_state", { label, flags });
|
||||
}
|
||||
|
||||
/**
|
||||
* Restore the state for the current window from disk.
|
||||
*/
|
||||
async function restoreStateCurrent(flags: StateFlags) {
|
||||
restoreState(getCurrent().label, flags);
|
||||
async function restoreStateCurrent(flags: StateFlags): Promise<void> {
|
||||
return restoreState(getCurrent().label, flags);
|
||||
}
|
||||
|
||||
export { restoreState, restoreStateCurrent, saveWindowState };
|
||||
|
||||
@@ -25,9 +25,9 @@
|
||||
"LICENSE"
|
||||
],
|
||||
"devDependencies": {
|
||||
"tslib": "^2.5.0"
|
||||
"tslib": "2.6.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^1.2.0"
|
||||
"@tauri-apps/api": "1.5.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import { createConfig } from "../../shared/rollup.config.mjs";
|
||||
export default createConfig({
|
||||
input: "guest-js/index.ts",
|
||||
pkg: JSON.parse(
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8")
|
||||
readFileSync(new URL("./package.json", import.meta.url), "utf8"),
|
||||
),
|
||||
external: [/^@tauri-apps\/api/],
|
||||
});
|
||||
|
||||
@@ -53,7 +53,7 @@ impl Default for StateFlags {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Deserialize, Serialize, PartialEq)]
|
||||
#[derive(Debug, Deserialize, Serialize, PartialEq)]
|
||||
struct WindowState {
|
||||
width: f64,
|
||||
height: f64,
|
||||
@@ -65,6 +65,21 @@ struct WindowState {
|
||||
fullscreen: bool,
|
||||
}
|
||||
|
||||
impl Default for WindowState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
width: Default::default(),
|
||||
height: Default::default(),
|
||||
x: Default::default(),
|
||||
y: Default::default(),
|
||||
maximized: Default::default(),
|
||||
visible: true,
|
||||
decorated: true,
|
||||
fullscreen: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct WindowStateCache(Arc<Mutex<HashMap<String, WindowState>>>);
|
||||
pub trait AppHandleExt {
|
||||
/// Saves all open windows state to disk
|
||||
@@ -175,7 +190,7 @@ impl<R: Runtime> WindowExt for Window<R> {
|
||||
}
|
||||
|
||||
if flags.contains(StateFlags::DECORATIONS) {
|
||||
metadata.visible = self.is_visible()?;
|
||||
metadata.decorated = self.is_decorated()?;
|
||||
}
|
||||
|
||||
if flags.contains(StateFlags::FULLSCREEN) {
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
../../shared/tsconfig.json
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"extends": "../../tsconfig.base.json",
|
||||
"include": ["guest-js/*.ts"]
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user