Merge branch 'v2' into feat/notification-mobile

pull/340/head
Lucas Nogueira 2 years ago
commit 6910342d34
No known key found for this signature in database
GPG Key ID: FFEA6C72E73482F1

@ -3,12 +3,12 @@
"pkgManagers": { "pkgManagers": {
"javascript": { "javascript": {
"version": true, "version": true,
"getPublishedVersion": "pnpm view ${ pkgFile.pkg.name } version", "getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js npm ${ pkgFile.pkg.name } ${ pkgFile.pkg.version }",
"publish": ["pnpm build", "pnpm publish --access public --no-git-checks"] "publish": ["pnpm build", "pnpm publish --access public --no-git-checks"]
}, },
"rust": { "rust": {
"version": true, "version": true,
"getPublishedVersion": "cargo search ${ pkgFile.pkg.package.name } --limit 1 | sed -nE 's/^[^\"]*\"//; s/\".*//1p' -", "getPublishedVersion": "node ../../.scripts/covector/package-latest-version.js cargo ${ pkgFile.pkg.package.name } ${ pkgFile.pkg.package.version }",
"publish": [ "publish": [
{ {
"command": "cargo package --no-verify", "command": "cargo package --no-verify",

@ -1,3 +1,4 @@
target target
node_modules node_modules
dist dist
dist-js

@ -6,7 +6,8 @@
"extends": [ "extends": [
"prettier", "prettier",
"eslint:recommended", "eslint:recommended",
"plugin:@typescript-eslint/recommended" "plugin:@typescript-eslint/recommended",
"plugin:security/recommended"
], ],
"overrides": [], "overrides": [],
"parser": "@typescript-eslint/parser", "parser": "@typescript-eslint/parser",

@ -6,14 +6,16 @@ on:
- cron: "0 0 * * *" - cron: "0 0 * * *"
push: push:
branches: branches:
- dev - v1
- 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:
- dev - v1
- v2
paths: paths:
- ".github/workflows/audit-javascript.yml" - ".github/workflows/audit-javascript.yml"
- "**/pnpm-lock.yaml" - "**/pnpm-lock.yaml"

@ -6,14 +6,16 @@ on:
- cron: "0 0 * * *" - cron: "0 0 * * *"
push: push:
branches: branches:
- dev - v1
- 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:
- dev - v1
- v2
paths: paths:
- ".github/workflows/audit-rust.yml" - ".github/workflows/audit-rust.yml"
- "**/Cargo.lock" - "**/Cargo.lock"

@ -3,7 +3,7 @@ name: version or publish
on: on:
push: push:
branches: branches:
- dev - v1
jobs: jobs:
version-or-publish: version-or-publish:

@ -3,7 +3,8 @@ name: Lint JavaScript
on: on:
push: push:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/lint-javascript.yml" - ".github/workflows/lint-javascript.yml"
- "plugins/*/guest-js/**" - "plugins/*/guest-js/**"
@ -13,7 +14,8 @@ on:
- "**/package.json" - "**/package.json"
pull_request: pull_request:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/lint-javascript.yml" - ".github/workflows/lint-javascript.yml"
- "plugins/*/guest-js/**" - "plugins/*/guest-js/**"

@ -3,14 +3,16 @@ name: Lint Rust
on: on:
push: push:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/lint-rust.yml" - ".github/workflows/lint-rust.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
- "**/Cargo.toml" - "**/Cargo.toml"
pull_request: pull_request:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/lint-rust.yml" - ".github/workflows/lint-rust.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
@ -32,7 +34,7 @@ jobs:
- name: install webkit2gtk and libudev for [authenticator] - name: install webkit2gtk and libudev for [authenticator]
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libudev-dev sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- name: Install clippy with stable toolchain - name: Install clippy with stable toolchain
uses: dtolnay/rust-toolchain@stable uses: dtolnay/rust-toolchain@stable

@ -3,7 +3,8 @@ name: Check MSRV
on: on:
push: push:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/msrv-check.yml" - ".github/workflows/msrv-check.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
@ -11,7 +12,8 @@ on:
- "**/Cargo.lock" - "**/Cargo.lock"
pull_request: pull_request:
branches: branches:
- dev - v1
- v2
paths: paths:
- ".github/workflows/msrv-check.yml" - ".github/workflows/msrv-check.yml"
- "plugins/*/src/**" - "plugins/*/src/**"
@ -34,7 +36,7 @@ jobs:
- name: install webkit2gtk and libudev for [authenticator] - name: install webkit2gtk and libudev for [authenticator]
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y webkit2gtk-4.0 libudev-dev sudo apt-get install -y libwebkit2gtk-4.0-dev libwebkit2gtk-4.1-dev libudev-dev
- uses: dtolnay/rust-toolchain@1.64.0 - uses: dtolnay/rust-toolchain@1.64.0

@ -4,8 +4,8 @@ on:
workflow_dispatch: workflow_dispatch:
push: push:
branches: branches:
- dev - v1
- next - v2
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}

@ -0,0 +1,56 @@
#!/usr/bin/env node
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
/*
This script is solely intended to be run as part of the `covector publish` step to
check the latest version of a crate, considering the current minor version.
*/
const https = require("https");
const kind = process.argv[2];
const packageName = process.argv[3];
const packageVersion = process.argv[4];
const target = packageVersion.substring(0, packageVersion.lastIndexOf("."));
let url = null;
switch (kind) {
case "cargo":
url = `https://crates.io/api/v1/crates/${packageName}`;
break;
case "npm":
url = `https://registry.npmjs.org/${packageName}`;
break;
default:
throw new Error("unexpected kind " + kind);
}
const options = {
headers: {
"Content-Type": "application/json",
Accept: "application/json",
"User-Agent": "tauri (https://github.com/tauri-apps/tauri)",
},
};
https.get(url, options, (response) => {
let chunks = [];
response.on("data", function (chunk) {
chunks.push(chunk);
});
response.on("end", function () {
const data = JSON.parse(chunks.join(""));
if (kind === "cargo") {
const versions = data.versions.filter((v) => v.num.startsWith(target));
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)
);
console.log(versions[versions.length - 1] || "0.0.0");
}
});
});

@ -21,6 +21,7 @@
"eslint-plugin-import": "^2.27.5", "eslint-plugin-import": "^2.27.5",
"eslint-plugin-n": "^15.7.0", "eslint-plugin-n": "^15.7.0",
"eslint-plugin-promise": "^6.1.1", "eslint-plugin-promise": "^6.1.1",
"eslint-plugin-security": "^1.7.1",
"prettier": "^2.8.7", "prettier": "^2.8.7",
"rollup": "^3.20.4", "rollup": "^3.20.4",
"typescript": "^5.0.4" "typescript": "^5.0.4"

@ -20,7 +20,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
[dependencies] [dependencies]
tauri-plugin-authenticator = "0.1" tauri-plugin-authenticator = "0.1"
# or through git # or through git
tauri-plugin-authenticator = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } 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: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-authenticator#next pnpm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-authenticator#next npm add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#next yarn add https://github.com/tauri-apps/tauri-plugin-authenticator#v2
``` ```
## Usage ## Usage
@ -53,7 +53,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 ```javascript
import { Authenticator } from 'tauri-plugin-authenticator-api'; import { Authenticator } from "tauri-plugin-authenticator-api";
const auth = new Authenticator(); const auth = new Authenticator();
auth.init(); // initialize transports auth.init(); // initialize transports
@ -63,16 +63,21 @@ const arr = new Uint32Array(32);
window.crypto.getRandomValues(arr); window.crypto.getRandomValues(arr);
const b64 = btoa(String.fromCharCode.apply(null, arr)); const b64 = btoa(String.fromCharCode.apply(null, arr));
// web-safe base64 // web-safe base64
const challenge = b64.replace(/\+/g, '-').replace(/\//g, '_'); const challenge = b64.replace(/\+/g, "-").replace(/\//g, "_");
const domain = 'https://tauri.app'; const domain = "https://tauri.app";
// attempt to register with the security key // attempt to register with the security key
const json = await auth.register(challenge, domain); const json = await auth.register(challenge, domain);
const registerResult = JSON.parse(json); const registerResult = JSON.parse(json);
// verify te registration was successfull // verify te registration was successfull
const r2 = await auth.verifyRegistration(challenge, app, registerResult.registerData, registerResult.clientData); const r2 = await auth.verifyRegistration(
challenge,
app,
registerResult.registerData,
registerResult.clientData
);
const j2 = JSON.parse(r2); const j2 = JSON.parse(r2);
// sign some data // sign some data
@ -80,10 +85,17 @@ const json = await auth.sign(challenge, app, keyHandle);
const signData = JSON.parse(json); const signData = JSON.parse(json);
// verify the signature again // verify the signature again
const counter = await auth.verifySignature(challenge, app, signData.signData, clientData, keyHandle, pubkey); const counter = await auth.verifySignature(
challenge,
app,
signData.signData,
clientData,
keyHandle,
pubkey
);
if (counter && counter > 0) { if (counter && counter > 0) {
console.log('SUCCESS!'); console.log("SUCCESS!");
} }
``` ```

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-autostart = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-autostart#next pnpm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-autostart#next npm add https://github.com/tauri-apps/tauri-plugin-autostart#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-autostart#next yarn add https://github.com/tauri-apps/tauri-plugin-autostart#v2
``` ```
## Usage ## Usage
@ -53,7 +53,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 ```javascript
import { enable, isEnabled, disable } from 'tauri-plugin-autostart-api'; import { enable, isEnabled, disable } from "tauri-plugin-autostart-api";
await enable(); await enable();

@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-cli#next pnpm add https://github.com/tauri-apps/tauri-plugin-cli#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-cli#next npm add https://github.com/tauri-apps/tauri-plugin-cli#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-cli#next yarn add https://github.com/tauri-apps/tauri-plugin-cli#v2
``` ```
## Usage ## Usage

@ -8,7 +8,7 @@
* @module * @module
*/ */
import { invoke } from '@tauri-apps/api/tauri'; import { invoke } from "@tauri-apps/api/tauri";
/** /**
* @since 1.0.0 * @since 1.0.0
@ -19,32 +19,32 @@ interface ArgMatch {
* boolean if flag * boolean if flag
* string[] or null if takes multiple values * string[] or null if takes multiple values
*/ */
value: string | boolean | string[] | null value: string | boolean | string[] | null;
/** /**
* Number of occurrences * Number of occurrences
*/ */
occurrences: number occurrences: number;
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface SubcommandMatch { interface SubcommandMatch {
name: string name: string;
matches: CliMatches matches: CliMatches;
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface CliMatches { interface CliMatches {
args: Record<string, ArgMatch> args: Record<string, ArgMatch>;
subcommand: SubcommandMatch | null subcommand: SubcommandMatch | null;
} }
/** /**
* Parse the arguments provided to the current process and get the matches using the configuration defined [`tauri.cli`](https://tauri.app/v1/api/config/#tauriconfig.cli) in `tauri.conf.json` * Parse the arguments provided to the current process and get the matches using the configuration defined [`tauri.cli`](https://tauri.app/v1/api/config/#tauriconfig.cli) in `tauri.conf.json`
* *
* @example * @example
* ```typescript * ```typescript
* import { getMatches } from 'tauri-plugin-cli-api'; * import { getMatches } from 'tauri-plugin-cli-api';
@ -64,9 +64,9 @@ interface CliMatches {
* @since 1.0.0 * @since 1.0.0
*/ */
async function getMatches(): Promise<CliMatches> { async function getMatches(): Promise<CliMatches> {
return await invoke('plugin:cli|cli_matches'); return await invoke("plugin:cli|cli_matches");
} }
export type { ArgMatch, SubcommandMatch, CliMatches } export type { ArgMatch, SubcommandMatch, CliMatches };
export { getMatches } export { getMatches };

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-clipboard = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-clipboard = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-clipboard#next pnpm add https://github.com/tauri-apps/tauri-plugin-clipboard#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-clipboard#next npm add https://github.com/tauri-apps/tauri-plugin-clipboard#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-clipboard#next yarn add https://github.com/tauri-apps/tauri-plugin-clipboard#v2
``` ```
## Usage ## Usage

@ -24,14 +24,14 @@
* @module * @module
*/ */
import { invoke } from '@tauri-apps/api/tauri' import { invoke } from "@tauri-apps/api/tauri";
interface Clip<K, T> { interface Clip<K, T> {
kind: K kind: K;
options: T options: T;
} }
type ClipResponse = Clip<'PlainText', string> type ClipResponse = Clip<"PlainText", string>;
/** /**
* Writes plain text to the clipboard. * Writes plain text to the clipboard.
@ -46,16 +46,19 @@ type ClipResponse = Clip<'PlainText', string>
* *
* @since 1.0.0. * @since 1.0.0.
*/ */
async function writeText(text: string, opts?: { label?: string }): Promise<void> { async function writeText(
return invoke('plugin:clipboard|write', { text: string,
opts?: { label?: string }
): Promise<void> {
return invoke("plugin:clipboard|write", {
data: { data: {
kind: 'PlainText', kind: "PlainText",
options: { options: {
label: opts?.label, label: opts?.label,
text text,
} },
} },
}) });
} }
/** /**
@ -68,8 +71,8 @@ async function writeText(text: string, opts?: { label?: string }): Promise<void>
* @since 1.0.0. * @since 1.0.0.
*/ */
async function readText(): Promise<string> { async function readText(): Promise<string> {
const kind: ClipResponse = await invoke('plugin:clipboard|read') const kind: ClipResponse = await invoke("plugin:clipboard|read");
return kind.options return kind.options;
} }
export { writeText, readText } export { writeText, readText };

@ -29,4 +29,4 @@
"dependencies": { "dependencies": {
"@tauri-apps/api": "^1.2.0" "@tauri-apps/api": "^1.2.0"
} }
} }

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-dialog-api = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-dialog-api = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:

@ -19,4 +19,4 @@
"svelte": "^3.49.0", "svelte": "^3.49.0",
"vite": "^3.0.2" "vite": "^3.0.2"
} }
} }

@ -1,116 +1,116 @@
{ {
"images" : [ "images": [
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-20x20@2x.png", "filename": "AppIcon-20x20@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-20x20@3x.png", "filename": "AppIcon-20x20@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-29x29@2x-1.png", "filename": "AppIcon-29x29@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-29x29@3x.png", "filename": "AppIcon-29x29@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-40x40@2x.png", "filename": "AppIcon-40x40@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-40x40@3x.png", "filename": "AppIcon-40x40@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "60x60", "size": "60x60",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-60x60@2x.png", "filename": "AppIcon-60x60@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "60x60", "size": "60x60",
"idiom" : "iphone", "idiom": "iphone",
"filename" : "AppIcon-60x60@3x.png", "filename": "AppIcon-60x60@3x.png",
"scale" : "3x" "scale": "3x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-20x20@1x.png", "filename": "AppIcon-20x20@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "20x20", "size": "20x20",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-20x20@2x-1.png", "filename": "AppIcon-20x20@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-29x29@1x.png", "filename": "AppIcon-29x29@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "29x29", "size": "29x29",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-29x29@2x.png", "filename": "AppIcon-29x29@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-40x40@1x.png", "filename": "AppIcon-40x40@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "40x40", "size": "40x40",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-40x40@2x-1.png", "filename": "AppIcon-40x40@2x-1.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "76x76", "size": "76x76",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-76x76@1x.png", "filename": "AppIcon-76x76@1x.png",
"scale" : "1x" "scale": "1x"
}, },
{ {
"size" : "76x76", "size": "76x76",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-76x76@2x.png", "filename": "AppIcon-76x76@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "83.5x83.5", "size": "83.5x83.5",
"idiom" : "ipad", "idiom": "ipad",
"filename" : "AppIcon-83.5x83.5@2x.png", "filename": "AppIcon-83.5x83.5@2x.png",
"scale" : "2x" "scale": "2x"
}, },
{ {
"size" : "1024x1024", "size": "1024x1024",
"idiom" : "ios-marketing", "idiom": "ios-marketing",
"filename" : "AppIcon-512@2x.png", "filename": "AppIcon-512@2x.png",
"scale" : "1x" "scale": "1x"
} }
], ],
"info" : { "info": {
"version" : 1, "version": 1,
"author" : "xcode" "author": "xcode"
} }
} }

@ -1,6 +1,6 @@
{ {
"info" : { "info": {
"version" : 1, "version": 1,
"author" : "xcode" "author": "xcode"
} }
} }

@ -60,7 +60,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/$(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/$(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/$(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/$(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/$(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/$(CONFIGURATION) $(SDKROOT)/usr/lib/swift $(TOOLCHAIN_DIR)/usr/lib/swift/$(PLATFORM_NAME) $(TOOLCHAIN_DIR)/usr/lib/swift-5.0/$(PLATFORM_NAME)
@ -82,4 +82,4 @@ targets:
basedOnDependencyAnalysis: false basedOnDependencyAnalysis: false
outputFiles: outputFiles:
- $(SRCROOT)/target/aarch64-apple-ios/${CONFIGURATION}/deps/libapp.a - $(SRCROOT)/target/aarch64-apple-ios/${CONFIGURATION}/deps/libapp.a
- $(SRCROOT)/target/x86_64-apple-ios/${CONFIGURATION}/deps/libapp.a - $(SRCROOT)/target/x86_64-apple-ios/${CONFIGURATION}/deps/libapp.a

@ -4,7 +4,11 @@ import { internalIpV4 } from "internal-ip";
// https://vitejs.dev/config/ // https://vitejs.dev/config/
export default defineConfig(async () => { export default defineConfig(async () => {
const host = process.env.TAURI_PLATFORM === 'android' || process.env.TAURI_PLATFORM === 'ios' ? (await internalIpV4()) : 'localhost' const host =
process.env.TAURI_PLATFORM === "android" ||
process.env.TAURI_PLATFORM === "ios"
? await internalIpV4()
: "localhost";
return { return {
plugins: [svelte()], plugins: [svelte()],
@ -13,17 +17,17 @@ export default defineConfig(async () => {
clearScreen: false, clearScreen: false,
// tauri expects a fixed port, fail if that port is not available // tauri expects a fixed port, fail if that port is not available
server: { server: {
host: '0.0.0.0', host: "0.0.0.0",
port: 5173, port: 5173,
strictPort: true, strictPort: true,
hmr: { hmr: {
protocol: 'ws', protocol: "ws",
host, host,
port: 5183 port: 5183,
}, },
fs: { fs: {
allow: ['.', '../../tooling/api/dist'] allow: [".", "../../tooling/api/dist"],
} },
}, },
// to make use of `TAURI_DEBUG` and other env variables // to make use of `TAURI_DEBUG` and other env variables
// https://tauri.studio/v1/api/config#buildconfig.beforedevcommand // https://tauri.studio/v1/api/config#buildconfig.beforedevcommand
@ -36,5 +40,5 @@ export default defineConfig(async () => {
// produce sourcemaps for debug builds // produce sourcemaps for debug builds
sourcemap: !!process.env.TAURI_DEBUG, sourcemap: !!process.env.TAURI_DEBUG,
}, },
} };
}); });

@ -2,18 +2,18 @@
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
import { invoke } from '@tauri-apps/api/tauri' import { invoke } from "@tauri-apps/api/tauri";
interface FileResponse { interface FileResponse {
base64Data?: string base64Data?: string;
duration?: number duration?: number;
height?: number height?: number;
width?: number width?: number;
mimeType?: string mimeType?: string;
modifiedAt?: number modifiedAt?: number;
name?: string name?: string;
path: string path: string;
size: number size: number;
} }
/** /**
@ -23,7 +23,7 @@ interface FileResponse {
*/ */
interface DialogFilter { interface DialogFilter {
/** Filter name. */ /** Filter name. */
name: string name: string;
/** /**
* Extensions to filter, without a `.` prefix. * Extensions to filter, without a `.` prefix.
* @example * @example
@ -31,7 +31,7 @@ interface DialogFilter {
* extensions: ['svg', 'png'] * extensions: ['svg', 'png']
* ``` * ```
*/ */
extensions: string[] extensions: string[];
} }
/** /**
@ -41,20 +41,20 @@ interface DialogFilter {
*/ */
interface OpenDialogOptions { interface OpenDialogOptions {
/** The title of the dialog window. */ /** The title of the dialog window. */
title?: string title?: string;
/** The filters of the dialog. */ /** The filters of the dialog. */
filters?: DialogFilter[] filters?: DialogFilter[];
/** Initial directory or file path. */ /** Initial directory or file path. */
defaultPath?: string defaultPath?: string;
/** Whether the dialog allows multiple selection or not. */ /** Whether the dialog allows multiple selection or not. */
multiple?: boolean multiple?: boolean;
/** Whether the dialog is a directory selection or not. */ /** Whether the dialog is a directory selection or not. */
directory?: boolean directory?: boolean;
/** /**
* If `directory` is true, indicates that it will be read recursively later. * If `directory` is true, indicates that it will be read recursively later.
* Defines whether subdirectories will be allowed on the scope or not. * Defines whether subdirectories will be allowed on the scope or not.
*/ */
recursive?: boolean recursive?: boolean;
} }
/** /**
@ -64,15 +64,15 @@ interface OpenDialogOptions {
*/ */
interface SaveDialogOptions { interface SaveDialogOptions {
/** The title of the dialog window. */ /** The title of the dialog window. */
title?: string title?: string;
/** The filters of the dialog. */ /** The filters of the dialog. */
filters?: DialogFilter[] filters?: DialogFilter[];
/** /**
* Initial directory or file path. * Initial directory or file path.
* If it's a directory path, the dialog interface will change to that folder. * If it's a directory path, the dialog interface will change to that folder.
* If it's not an existing directory, the file name will be set to the dialog's file name input and the dialog will be set to the parent folder. * If it's not an existing directory, the file name will be set to the dialog's file name input and the dialog will be set to the parent folder.
*/ */
defaultPath?: string defaultPath?: string;
} }
/** /**
@ -80,36 +80,36 @@ interface SaveDialogOptions {
*/ */
interface MessageDialogOptions { interface MessageDialogOptions {
/** The title of the dialog. Defaults to the app name. */ /** The title of the dialog. Defaults to the app name. */
title?: string title?: string;
/** The type of the dialog. Defaults to `info`. */ /** The type of the dialog. Defaults to `info`. */
type?: 'info' | 'warning' | 'error' type?: "info" | "warning" | "error";
/** The label of the confirm button. */ /** The label of the confirm button. */
okLabel?: string okLabel?: string;
} }
interface ConfirmDialogOptions { interface ConfirmDialogOptions {
/** The title of the dialog. Defaults to the app name. */ /** The title of the dialog. Defaults to the app name. */
title?: string title?: string;
/** The type of the dialog. Defaults to `info`. */ /** The type of the dialog. Defaults to `info`. */
type?: 'info' | 'warning' | 'error' type?: "info" | "warning" | "error";
/** The label of the confirm button. */ /** The label of the confirm button. */
okLabel?: string okLabel?: string;
/** The label of the cancel button. */ /** The label of the cancel button. */
cancelLabel?: string cancelLabel?: string;
} }
async function open( async function open(
options?: OpenDialogOptions & { multiple?: false, directory?: false } options?: OpenDialogOptions & { multiple?: false; directory?: false }
): Promise<null | FileResponse> ): Promise<null | FileResponse>;
async function open( async function open(
options?: OpenDialogOptions & { multiple?: true, directory?: false } options?: OpenDialogOptions & { multiple?: true; directory?: false }
): Promise<null | FileResponse[]> ): Promise<null | FileResponse[]>;
async function open( async function open(
options?: OpenDialogOptions & { multiple?: false, directory?: true } options?: OpenDialogOptions & { multiple?: false; directory?: true }
): Promise<null | string> ): Promise<null | string>;
async function open( async function open(
options?: OpenDialogOptions & { multiple?: true, directory?: true } options?: OpenDialogOptions & { multiple?: true; directory?: true }
): Promise<null | string[]> ): Promise<null | string[]>;
/** /**
* Open a file/directory selection dialog. * Open a file/directory selection dialog.
* *
@ -165,11 +165,11 @@ async function open(
async function open( async function open(
options: OpenDialogOptions = {} options: OpenDialogOptions = {}
): Promise<null | string | string[] | FileResponse | FileResponse[]> { ): Promise<null | string | string[] | FileResponse | FileResponse[]> {
if (typeof options === 'object') { if (typeof options === "object") {
Object.freeze(options) Object.freeze(options);
} }
return invoke('plugin:dialog|open', { options }) return invoke("plugin:dialog|open", { options });
} }
/** /**
@ -197,11 +197,11 @@ async function open(
* @since 1.0.0 * @since 1.0.0
*/ */
async function save(options: SaveDialogOptions = {}): Promise<string | null> { async function save(options: SaveDialogOptions = {}): Promise<string | null> {
if (typeof options === 'object') { if (typeof options === "object") {
Object.freeze(options) Object.freeze(options);
} }
return invoke('plugin:dialog|save', { options }) return invoke("plugin:dialog|save", { options });
} }
/** /**
@ -225,13 +225,13 @@ async function message(
message: string, message: string,
options?: string | MessageDialogOptions options?: string | MessageDialogOptions
): Promise<void> { ): Promise<void> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === "string" ? { title: options } : options;
return invoke('plugin:dialog|message', { return invoke("plugin:dialog|message", {
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type_: opts?.type, type_: opts?.type,
okButtonLabel: opts?.okLabel?.toString() okButtonLabel: opts?.okLabel?.toString(),
}) });
} }
/** /**
@ -254,14 +254,14 @@ async function ask(
message: string, message: string,
options?: string | ConfirmDialogOptions options?: string | ConfirmDialogOptions
): Promise<boolean> { ): Promise<boolean> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === "string" ? { title: options } : options;
return invoke('plugin:dialog|ask', { return invoke("plugin:dialog|ask", {
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type_: opts?.type, type_: opts?.type,
okButtonLabel: opts?.okLabel?.toString() ?? 'Yes', okButtonLabel: opts?.okLabel?.toString() ?? "Yes",
cancelButtonLabel: opts?.cancelLabel?.toString() ?? 'No', cancelButtonLabel: opts?.cancelLabel?.toString() ?? "No",
}) });
} }
/** /**
@ -284,14 +284,14 @@ async function confirm(
message: string, message: string,
options?: string | ConfirmDialogOptions options?: string | ConfirmDialogOptions
): Promise<boolean> { ): Promise<boolean> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === "string" ? { title: options } : options;
return invoke('plugin:dialog|confirm', { return invoke("plugin:dialog|confirm", {
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type_: opts?.type, type_: opts?.type,
okButtonLabel: opts?.okLabel?.toString() ?? 'Ok', okButtonLabel: opts?.okLabel?.toString() ?? "Ok",
cancelButtonLabel: opts?.cancelLabel?.toString() ?? 'Cancel', cancelButtonLabel: opts?.cancelLabel?.toString() ?? "Cancel",
}) });
} }
export type { export type {
@ -299,7 +299,7 @@ export type {
OpenDialogOptions, OpenDialogOptions,
SaveDialogOptions, SaveDialogOptions,
MessageDialogOptions, MessageDialogOptions,
ConfirmDialogOptions ConfirmDialogOptions,
} };
export { open, save, message, ask, confirm } export { open, save, message, ask, confirm };

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-fs-watch = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-fs-watch = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-fs-watch#next pnpm add https://github.com/tauri-apps/tauri-plugin-fs-watch#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-fs-watch#next npm add https://github.com/tauri-apps/tauri-plugin-fs-watch#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-fs-watch#next yarn add https://github.com/tauri-apps/tauri-plugin-fs-watch#v2
``` ```
## Usage ## Usage
@ -51,16 +51,24 @@ 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 ```javascript
import { watch, watchImmediate } from 'tauri-plugin-fs-watch-api'; import { watch, watchImmediate } from "tauri-plugin-fs-watch-api";
// can also watch an array of paths // can also watch an array of paths
const stopWatching = await watch('/path/to/something', { recursive: true }, (event) => { const stopWatching = await watch(
"/path/to/something",
(event) => {
const { type, payload } = event; const { type, payload } = event;
}); },
{ recursive: true }
);
const stopRawWatcher = await watchImmediate(['/path/a', '/path/b'], {}, (event) => { const stopRawWatcher = await watchImmediate(
["/path/a", "/path/b"],
(event) => {
const { path, operation, cookie } = event; const { path, operation, cookie } = event;
}); },
{}
);
``` ```
## Contributing ## Contributing

@ -44,8 +44,8 @@ async function unwatch(id: number): Promise<void> {
export async function watch( export async function watch(
paths: string | string[], paths: string | string[],
options: DebouncedWatchOptions, cb: (event: DebouncedEvent) => void,
cb: (event: DebouncedEvent) => void options: DebouncedWatchOptions = {}
): Promise<UnlistenFn> { ): Promise<UnlistenFn> {
const opts = { const opts = {
recursive: false, recursive: false,
@ -82,8 +82,8 @@ export async function watch(
export async function watchImmediate( export async function watchImmediate(
paths: string | string[], paths: string | string[],
options: WatchOptions, cb: (event: RawEvent) => void,
cb: (event: RawEvent) => void options: WatchOptions = {}
): Promise<UnlistenFn> { ): Promise<UnlistenFn> {
const opts = { const opts = {
recursive: false, recursive: false,

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-fs = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-fs#next pnpm add https://github.com/tauri-apps/tauri-plugin-fs#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-fs#next npm add https://github.com/tauri-apps/tauri-plugin-fs#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-fs#next yarn add https://github.com/tauri-apps/tauri-plugin-fs#v2
``` ```
## Usage ## Usage
@ -51,9 +51,9 @@ 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 ```javascript
import { metadata } from 'tauri-plugin-fs-api'; import { metadata } from "tauri-plugin-fs-api";
await metadata('/path/to/file'); await metadata("/path/to/file");
``` ```
## Contributing ## Contributing

@ -210,14 +210,14 @@ enum BaseDirectory {
Font, Font,
Home, Home,
Runtime, Runtime,
Template Template,
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface FsOptions { interface FsOptions {
dir?: BaseDirectory dir?: BaseDirectory;
// note that adding fields here needs a change in the writeBinaryFile check // note that adding fields here needs a change in the writeBinaryFile check
} }
@ -225,8 +225,8 @@ interface FsOptions {
* @since 1.0.0 * @since 1.0.0
*/ */
interface FsDirOptions { interface FsDirOptions {
dir?: BaseDirectory dir?: BaseDirectory;
recursive?: boolean recursive?: boolean;
} }
/** /**
@ -236,12 +236,12 @@ interface FsDirOptions {
*/ */
interface FsTextFileOption { interface FsTextFileOption {
/** Path to the file to write. */ /** Path to the file to write. */
path: string path: string;
/** The UTF-8 string to write to the file. */ /** The UTF-8 string to write to the file. */
contents: string contents: string;
} }
type BinaryFileContents = Iterable<number> | ArrayLike<number> | ArrayBuffer type BinaryFileContents = Iterable<number> | ArrayLike<number> | ArrayBuffer;
/** /**
* Options object used to write a binary data to a file. * Options object used to write a binary data to a file.
@ -250,23 +250,23 @@ type BinaryFileContents = Iterable<number> | ArrayLike<number> | ArrayBuffer
*/ */
interface FsBinaryFileOption { interface FsBinaryFileOption {
/** Path to the file to write. */ /** Path to the file to write. */
path: string path: string;
/** The byte array contents. */ /** The byte array contents. */
contents: BinaryFileContents contents: BinaryFileContents;
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface FileEntry { interface FileEntry {
path: string path: string;
/** /**
* Name of the directory/file * Name of the directory/file
* can be null if the path terminates with `..` * can be null if the path terminates with `..`
*/ */
name?: string name?: string;
/** Children of this entry if it's a directory; null otherwise */ /** Children of this entry if it's a directory; null otherwise */
children?: FileEntry[] children?: FileEntry[];
} }
/** /**
@ -286,8 +286,8 @@ async function readTextFile(
): Promise<string> { ): Promise<string> {
return await invoke("plugin:fs|read_text_file", { return await invoke("plugin:fs|read_text_file", {
path: filePath, path: filePath,
options options,
}) });
} }
/** /**
@ -307,10 +307,10 @@ async function readBinaryFile(
): Promise<Uint8Array> { ): Promise<Uint8Array> {
const arr = await invoke<number[]>("plugin:fs|read_file", { const arr = await invoke<number[]>("plugin:fs|read_file", {
path: filePath, path: filePath,
options options,
}) });
return Uint8Array.from(arr) return Uint8Array.from(arr);
} }
/** /**
@ -328,7 +328,7 @@ async function writeTextFile(
path: string, path: string,
contents: string, contents: string,
options?: FsOptions options?: FsOptions
): Promise<void> ): Promise<void>;
/** /**
* Writes a UTF-8 text file. * Writes a UTF-8 text file.
@ -345,7 +345,7 @@ async function writeTextFile(
async function writeTextFile( async function writeTextFile(
file: FsTextFileOption, file: FsTextFileOption,
options?: FsOptions options?: FsOptions
): Promise<void> ): Promise<void>;
/** /**
* Writes a UTF-8 text file. * Writes a UTF-8 text file.
@ -359,33 +359,33 @@ async function writeTextFile(
contents?: string | FsOptions, contents?: string | FsOptions,
options?: FsOptions options?: FsOptions
): Promise<void> { ): Promise<void> {
if (typeof options === 'object') { if (typeof options === "object") {
Object.freeze(options) Object.freeze(options);
} }
if (typeof path === 'object') { if (typeof path === "object") {
Object.freeze(path) Object.freeze(path);
} }
const file: FsTextFileOption = { path: '', contents: '' } const file: FsTextFileOption = { path: "", contents: "" };
let fileOptions: FsOptions | undefined = options let fileOptions: FsOptions | undefined = options;
if (typeof path === 'string') { if (typeof path === "string") {
file.path = path file.path = path;
} else { } else {
file.path = path.path file.path = path.path;
file.contents = path.contents file.contents = path.contents;
} }
if (typeof contents === 'string') { if (typeof contents === "string") {
file.contents = contents ?? '' file.contents = contents ?? "";
} else { } else {
fileOptions = contents fileOptions = contents;
} }
return await invoke("plugin:fs|write_file", { return await invoke("plugin:fs|write_file", {
path: file.path, path: file.path,
contents: Array.from(new TextEncoder().encode(file.contents)), contents: Array.from(new TextEncoder().encode(file.contents)),
options: fileOptions options: fileOptions,
}) });
} }
/** /**
@ -406,7 +406,7 @@ async function writeBinaryFile(
path: string, path: string,
contents: BinaryFileContents, contents: BinaryFileContents,
options?: FsOptions options?: FsOptions
): Promise<void> ): Promise<void>;
/** /**
* Writes a byte array content to a file. * Writes a byte array content to a file.
@ -426,7 +426,7 @@ async function writeBinaryFile(
async function writeBinaryFile( async function writeBinaryFile(
file: FsBinaryFileOption, file: FsBinaryFileOption,
options?: FsOptions options?: FsOptions
): Promise<void> ): Promise<void>;
/** /**
* Writes a byte array content to a file. * Writes a byte array content to a file.
@ -440,27 +440,27 @@ async function writeBinaryFile(
contents?: BinaryFileContents | FsOptions, contents?: BinaryFileContents | FsOptions,
options?: FsOptions options?: FsOptions
): Promise<void> { ): Promise<void> {
if (typeof options === 'object') { if (typeof options === "object") {
Object.freeze(options) Object.freeze(options);
} }
if (typeof path === 'object') { if (typeof path === "object") {
Object.freeze(path) Object.freeze(path);
} }
const file: FsBinaryFileOption = { path: '', contents: [] } const file: FsBinaryFileOption = { path: "", contents: [] };
let fileOptions: FsOptions | undefined = options let fileOptions: FsOptions | undefined = options;
if (typeof path === 'string') { if (typeof path === "string") {
file.path = path file.path = path;
} else { } else {
file.path = path.path file.path = path.path;
file.contents = path.contents file.contents = path.contents;
} }
if (contents && 'dir' in contents) { if (contents && "dir" in contents) {
fileOptions = contents fileOptions = contents;
} else if (typeof path === 'string') { } else if (typeof path === "string") {
// @ts-expect-error in this case `contents` is always a BinaryFileContents // @ts-expect-error in this case `contents` is always a BinaryFileContents
file.contents = contents ?? [] file.contents = contents ?? [];
} }
return await invoke("plugin:fs|write_binary_file", { return await invoke("plugin:fs|write_binary_file", {
@ -470,8 +470,8 @@ async function writeBinaryFile(
? new Uint8Array(file.contents) ? new Uint8Array(file.contents)
: file.contents : file.contents
), ),
options: fileOptions options: fileOptions,
}) });
} }
/** /**
@ -500,8 +500,8 @@ async function readDir(
): Promise<FileEntry[]> { ): Promise<FileEntry[]> {
return await invoke("plugin:fs|read_dir", { return await invoke("plugin:fs|read_dir", {
path: dir, path: dir,
options options,
}) });
} }
/** /**
@ -525,8 +525,8 @@ async function createDir(
): Promise<void> { ): Promise<void> {
return await invoke("plugin:fs|create_dir", { return await invoke("plugin:fs|create_dir", {
path: dir, path: dir,
options options,
}) });
} }
/** /**
@ -549,8 +549,8 @@ async function removeDir(
): Promise<void> { ): Promise<void> {
return await invoke("plugin:fs|remove_dir", { return await invoke("plugin:fs|remove_dir", {
path: dir, path: dir,
options options,
}) });
} }
/** /**
@ -574,8 +574,8 @@ async function copyFile(
return await invoke("plugin:fs|copy_file", { return await invoke("plugin:fs|copy_file", {
source, source,
destination, destination,
options options,
}) });
} }
/** /**
@ -597,8 +597,8 @@ async function removeFile(
): Promise<void> { ): Promise<void> {
return await invoke("plugin:fs|remove_file", { return await invoke("plugin:fs|remove_file", {
path: file, path: file,
options options,
}) });
} }
/** /**
@ -622,9 +622,8 @@ async function renameFile(
return await invoke("plugin:fs|rename_file", { return await invoke("plugin:fs|rename_file", {
oldPath, oldPath,
newPath, newPath,
options options,
});
})
} }
/** /**
@ -644,7 +643,7 @@ async function exists(path: string): Promise<boolean> {
/** /**
* Returns the metadata for the given path. * Returns the metadata for the given path.
* *
* @since 1.0.0 * @since 1.0.0
*/ */
async function metadata(path: string): Promise<Metadata> { async function metadata(path: string): Promise<Metadata> {
@ -670,7 +669,7 @@ export type {
FileEntry, FileEntry,
Permissions, Permissions,
Metadata, Metadata,
} };
export { export {
BaseDirectory, BaseDirectory,
@ -687,5 +686,5 @@ export {
removeFile, removeFile,
renameFile, renameFile,
exists, exists,
metadata metadata,
} };

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-shortcut = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-shortcut = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-shortcut#next pnpm add https://github.com/tauri-apps/tauri-plugin-shortcut#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-shortcut#next npm add https://github.com/tauri-apps/tauri-plugin-shortcut#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-shortcut#next yarn add https://github.com/tauri-apps/tauri-plugin-shortcut#v2
``` ```
## Usage ## Usage

@ -21,9 +21,9 @@
* @module * @module
*/ */
import { invoke, transformCallback } from '@tauri-apps/api/tauri' import { invoke, transformCallback } from "@tauri-apps/api/tauri";
export type ShortcutHandler = (shortcut: string) => void export type ShortcutHandler = (shortcut: string) => void;
/** /**
* Register a global shortcut. * Register a global shortcut.
@ -44,10 +44,10 @@ async function register(
shortcut: string, shortcut: string,
handler: ShortcutHandler handler: ShortcutHandler
): Promise<void> { ): Promise<void> {
return await invoke('plugin:globalShortcut|register', { return await invoke("plugin:globalShortcut|register", {
shortcut, shortcut,
handler: transformCallback(handler) handler: transformCallback(handler),
}) });
} }
/** /**
@ -69,15 +69,15 @@ async function registerAll(
shortcuts: string[], shortcuts: string[],
handler: ShortcutHandler handler: ShortcutHandler
): Promise<void> { ): Promise<void> {
return await invoke('plugin:globalShortcut|register_all', { return await invoke("plugin:globalShortcut|register_all", {
shortcuts, shortcuts,
handler: transformCallback(handler) handler: transformCallback(handler),
}) });
} }
/** /**
* Determines whether the given shortcut is registered by this application or not. * Determines whether the given shortcut is registered by this application or not.
* *
* If the shortcut is registered by another application, it will still return `false`. * If the shortcut is registered by another application, it will still return `false`.
* *
* @example * @example
@ -91,9 +91,9 @@ async function registerAll(
* @since 1.0.0 * @since 1.0.0
*/ */
async function isRegistered(shortcut: string): Promise<boolean> { async function isRegistered(shortcut: string): Promise<boolean> {
return await invoke('plugin:globalShortcut|is_registered', { return await invoke("plugin:globalShortcut|is_registered", {
shortcut shortcut,
}) });
} }
/** /**
@ -109,9 +109,9 @@ async function isRegistered(shortcut: string): Promise<boolean> {
* @since 1.0.0 * @since 1.0.0
*/ */
async function unregister(shortcut: string): Promise<void> { async function unregister(shortcut: string): Promise<void> {
return await invoke('plugin:globalShortcut|unregister', { return await invoke("plugin:globalShortcut|unregister", {
shortcut shortcut,
}) });
} }
/** /**
@ -125,7 +125,7 @@ async function unregister(shortcut: string): Promise<void> {
* @since 1.0.0 * @since 1.0.0
*/ */
async function unregisterAll(): Promise<void> { async function unregisterAll(): Promise<void> {
return await invoke('plugin:globalShortcut|unregister_all') return await invoke("plugin:globalShortcut|unregister_all");
} }
export { register, registerAll, isRegistered, unregister, unregisterAll } export { register, registerAll, isRegistered, unregister, unregisterAll };

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-http = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-fs-extra = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-http#next pnpm add https://github.com/tauri-apps/tauri-plugin-http#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-http#next npm add https://github.com/tauri-apps/tauri-plugin-http#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-http#next yarn add https://github.com/tauri-apps/tauri-plugin-http#v2
``` ```
## Usage ## Usage

@ -41,14 +41,14 @@
* @module * @module
*/ */
import { invoke } from '@tauri-apps/api/tauri' import { invoke } from "@tauri-apps/api/tauri";
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface Duration { interface Duration {
secs: number secs: number;
nanos: number nanos: number;
} }
/** /**
@ -59,8 +59,8 @@ interface ClientOptions {
* Defines the maximum number of redirects the client should follow. * Defines the maximum number of redirects the client should follow.
* If set to 0, no redirects will be followed. * If set to 0, no redirects will be followed.
*/ */
maxRedirections?: number maxRedirections?: number;
connectTimeout?: number | Duration connectTimeout?: number | Duration;
} }
/** /**
@ -69,19 +69,19 @@ interface ClientOptions {
enum ResponseType { enum ResponseType {
JSON = 1, JSON = 1,
Text = 2, Text = 2,
Binary = 3 Binary = 3,
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface FilePart<T> { interface FilePart<T> {
file: string | T file: string | T;
mime?: string mime?: string;
fileName?: string fileName?: string;
} }
type Part = string | Uint8Array | FilePart<Uint8Array> type Part = string | Uint8Array | FilePart<Uint8Array>;
/** /**
* The body object to be used on POST and PUT requests. * The body object to be used on POST and PUT requests.
@ -89,13 +89,13 @@ type Part = string | Uint8Array | FilePart<Uint8Array>
* @since 1.0.0 * @since 1.0.0
*/ */
class Body { class Body {
type: string type: string;
payload: unknown payload: unknown;
/** @ignore */ /** @ignore */
private constructor(type: string, payload: unknown) { private constructor(type: string, payload: unknown) {
this.type = type this.type = type;
this.payload = payload this.payload = payload;
} }
/** /**
@ -130,39 +130,39 @@ class Body {
* @returns The body object ready to be used on the POST and PUT requests. * @returns The body object ready to be used on the POST and PUT requests.
*/ */
static form(data: Record<string, Part> | FormData): Body { static form(data: Record<string, Part> | FormData): Body {
const form: Record<string, string | number[] | FilePart<number[]>> = {} const form: Record<string, string | number[] | FilePart<number[]>> = {};
const append = ( const append = (
key: string, key: string,
v: string | Uint8Array | FilePart<Uint8Array> | File v: string | Uint8Array | FilePart<Uint8Array> | File
): void => { ): void => {
if (v !== null) { if (v !== null) {
let r let r;
if (typeof v === 'string') { if (typeof v === "string") {
r = v r = v;
} else if (v instanceof Uint8Array || Array.isArray(v)) { } else if (v instanceof Uint8Array || Array.isArray(v)) {
r = Array.from(v) r = Array.from(v);
} else if (v instanceof File) { } else if (v instanceof File) {
r = { file: v.name, mime: v.type, fileName: v.name } r = { file: v.name, mime: v.type, fileName: v.name };
} else if (typeof v.file === 'string') { } else if (typeof v.file === "string") {
r = { file: v.file, mime: v.mime, fileName: v.fileName } r = { file: v.file, mime: v.mime, fileName: v.fileName };
} else { } else {
r = { file: Array.from(v.file), mime: v.mime, fileName: v.fileName } r = { file: Array.from(v.file), mime: v.mime, fileName: v.fileName };
} }
form[String(key)] = r form[String(key)] = r;
} }
} };
if (data instanceof FormData) { if (data instanceof FormData) {
for (const [key, value] of data) { for (const [key, value] of data) {
append(key, value) append(key, value);
} }
} else { } else {
for (const [key, value] of Object.entries(data)) { for (const [key, value] of Object.entries(data)) {
append(key, value) append(key, value);
} }
} }
return new Body('Form', form) return new Body("Form", form);
} }
/** /**
@ -181,7 +181,7 @@ class Body {
* @returns The body object ready to be used on the POST and PUT requests. * @returns The body object ready to be used on the POST and PUT requests.
*/ */
static json<K extends string | number | symbol, V>(data: Record<K, V>): Body { static json<K extends string | number | symbol, V>(data: Record<K, V>): Body {
return new Body('Json', data) return new Body("Json", data);
} }
/** /**
@ -197,7 +197,7 @@ class Body {
* @returns The body object ready to be used on the POST and PUT requests. * @returns The body object ready to be used on the POST and PUT requests.
*/ */
static text(value: string): Body { static text(value: string): Body {
return new Body('Text', value) return new Body("Text", value);
} }
/** /**
@ -217,23 +217,23 @@ class Body {
): Body { ): Body {
// stringifying Uint8Array doesn't return an array of numbers, so we create one here // stringifying Uint8Array doesn't return an array of numbers, so we create one here
return new Body( return new Body(
'Bytes', "Bytes",
Array.from(bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes) Array.from(bytes instanceof ArrayBuffer ? new Uint8Array(bytes) : bytes)
) );
} }
} }
/** The request HTTP verb. */ /** The request HTTP verb. */
type HttpVerb = type HttpVerb =
| 'GET' | "GET"
| 'POST' | "POST"
| 'PUT' | "PUT"
| 'DELETE' | "DELETE"
| 'PATCH' | "PATCH"
| 'HEAD' | "HEAD"
| 'OPTIONS' | "OPTIONS"
| 'CONNECT' | "CONNECT"
| 'TRACE' | "TRACE";
/** /**
* Options object sent to the backend. * Options object sent to the backend.
@ -241,27 +241,27 @@ type HttpVerb =
* @since 1.0.0 * @since 1.0.0
*/ */
interface HttpOptions { interface HttpOptions {
method: HttpVerb method: HttpVerb;
url: string url: string;
headers?: Record<string, unknown> headers?: Record<string, unknown>;
query?: Record<string, unknown> query?: Record<string, unknown>;
body?: Body body?: Body;
timeout?: number | Duration timeout?: number | Duration;
responseType?: ResponseType responseType?: ResponseType;
} }
/** Request options. */ /** Request options. */
type RequestOptions = Omit<HttpOptions, 'method' | 'url'> type RequestOptions = Omit<HttpOptions, "method" | "url">;
/** Options for the `fetch` API. */ /** Options for the `fetch` API. */
type FetchOptions = Omit<HttpOptions, 'url'> type FetchOptions = Omit<HttpOptions, "url">;
/** @ignore */ /** @ignore */
interface IResponse<T> { interface IResponse<T> {
url: string url: string;
status: number status: number;
headers: Record<string, string> headers: Record<string, string>;
rawHeaders: Record<string, string[]> rawHeaders: Record<string, string[]>;
data: T data: T;
} }
/** /**
@ -271,26 +271,26 @@ interface IResponse<T> {
* */ * */
class Response<T> { class Response<T> {
/** The request URL. */ /** The request URL. */
url: string url: string;
/** The response status code. */ /** The response status code. */
status: number status: number;
/** A boolean indicating whether the response was successful (status in the range 200299) or not. */ /** A boolean indicating whether the response was successful (status in the range 200299) or not. */
ok: boolean ok: boolean;
/** The response headers. */ /** The response headers. */
headers: Record<string, string> headers: Record<string, string>;
/** The response raw headers. */ /** The response raw headers. */
rawHeaders: Record<string, string[]> rawHeaders: Record<string, string[]>;
/** The response data. */ /** The response data. */
data: T data: T;
/** @ignore */ /** @ignore */
constructor(response: IResponse<T>) { constructor(response: IResponse<T>) {
this.url = response.url this.url = response.url;
this.status = response.status this.status = response.status;
this.ok = this.status >= 200 && this.status < 300 this.ok = this.status >= 200 && this.status < 300;
this.headers = response.headers this.headers = response.headers;
this.rawHeaders = response.rawHeaders this.rawHeaders = response.rawHeaders;
this.data = response.data this.data = response.data;
} }
} }
@ -298,10 +298,10 @@ class Response<T> {
* @since 1.0.0 * @since 1.0.0
*/ */
class Client { class Client {
id: number id: number;
/** @ignore */ /** @ignore */
constructor(id: number) { constructor(id: number) {
this.id = id this.id = id;
} }
/** /**
@ -314,9 +314,9 @@ class Client {
* ``` * ```
*/ */
async drop(): Promise<void> { async drop(): Promise<void> {
return invoke('plugin:http|drop_client', { return invoke("plugin:http|drop_client", {
client: this.id client: this.id,
}) });
} }
/** /**
@ -333,34 +333,34 @@ class Client {
*/ */
async request<T>(options: HttpOptions): Promise<Response<T>> { async request<T>(options: HttpOptions): Promise<Response<T>> {
const jsonResponse = const jsonResponse =
!options.responseType || options.responseType === ResponseType.JSON !options.responseType || options.responseType === ResponseType.JSON;
if (jsonResponse) { if (jsonResponse) {
options.responseType = ResponseType.Text options.responseType = ResponseType.Text;
} }
return invoke<IResponse<T>>('plugin:http|request', { return invoke<IResponse<T>>("plugin:http|request", {
client: this.id, clientId: this.id,
options options,
}).then((res) => { }).then((res) => {
const response = new Response(res) const response = new Response(res);
if (jsonResponse) { if (jsonResponse) {
/* eslint-disable */ /* eslint-disable */
try { try {
response.data = JSON.parse(response.data as string) response.data = JSON.parse(response.data as string);
} catch (e) { } catch (e) {
if (response.ok && (response.data as unknown as string) === '') { if (response.ok && (response.data as unknown as string) === "") {
response.data = {} as T response.data = {} as T;
} else if (response.ok) { } else if (response.ok) {
throw Error( throw Error(
`Failed to parse response \`${response.data}\` as JSON: ${e}; `Failed to parse response \`${response.data}\` as JSON: ${e};
try setting the \`responseType\` option to \`ResponseType.Text\` or \`ResponseType.Binary\` if the API does not return a JSON response.` try setting the \`responseType\` option to \`ResponseType.Text\` or \`ResponseType.Binary\` if the API does not return a JSON response.`
) );
} }
} }
/* eslint-enable */ /* eslint-enable */
return response return response;
} }
return response return response;
}) });
} }
/** /**
@ -378,10 +378,10 @@ class Client {
*/ */
async get<T>(url: string, options?: RequestOptions): Promise<Response<T>> { async get<T>(url: string, options?: RequestOptions): Promise<Response<T>> {
return this.request({ return this.request({
method: 'GET', method: "GET",
url, url,
...options ...options,
}) });
} }
/** /**
@ -406,11 +406,11 @@ class Client {
options?: RequestOptions options?: RequestOptions
): Promise<Response<T>> { ): Promise<Response<T>> {
return this.request({ return this.request({
method: 'POST', method: "POST",
url, url,
body, body,
...options ...options,
}) });
} }
/** /**
@ -436,11 +436,11 @@ class Client {
options?: RequestOptions options?: RequestOptions
): Promise<Response<T>> { ): Promise<Response<T>> {
return this.request({ return this.request({
method: 'PUT', method: "PUT",
url, url,
body, body,
...options ...options,
}) });
} }
/** /**
@ -456,10 +456,10 @@ class Client {
*/ */
async patch<T>(url: string, options?: RequestOptions): Promise<Response<T>> { async patch<T>(url: string, options?: RequestOptions): Promise<Response<T>> {
return this.request({ return this.request({
method: 'PATCH', method: "PATCH",
url, url,
...options ...options,
}) });
} }
/** /**
@ -473,10 +473,10 @@ class Client {
*/ */
async delete<T>(url: string, options?: RequestOptions): Promise<Response<T>> { async delete<T>(url: string, options?: RequestOptions): Promise<Response<T>> {
return this.request({ return this.request({
method: 'DELETE', method: "DELETE",
url, url,
...options ...options,
}) });
} }
} }
@ -495,13 +495,13 @@ class Client {
* @since 1.0.0 * @since 1.0.0
*/ */
async function getClient(options?: ClientOptions): Promise<Client> { async function getClient(options?: ClientOptions): Promise<Client> {
return invoke<number>('plugin:http|create_client', { return invoke<number>("plugin:http|create_client", {
options options,
}).then((id) => new Client(id)) }).then((id) => new Client(id));
} }
/** @internal */ /** @internal */
let defaultClient: Client | null = null let defaultClient: Client | null = null;
/** /**
* Perform an HTTP request using the default client. * Perform an HTTP request using the default client.
@ -519,13 +519,13 @@ async function fetch<T>(
options?: FetchOptions options?: FetchOptions
): Promise<Response<T>> { ): Promise<Response<T>> {
if (defaultClient === null) { if (defaultClient === null) {
defaultClient = await getClient() defaultClient = await getClient();
} }
return defaultClient.request({ return defaultClient.request({
url, url,
method: options?.method ?? 'GET', method: options?.method ?? "GET",
...options ...options,
}) });
} }
export type { export type {
@ -535,7 +535,15 @@ export type {
HttpVerb, HttpVerb,
HttpOptions, HttpOptions,
RequestOptions, RequestOptions,
FetchOptions FetchOptions,
} };
export { getClient, fetch, Body, Client, Response, ResponseType, type FilePart } export {
getClient,
fetch,
Body,
Client,
Response,
ResponseType,
type FilePart,
};

@ -20,7 +20,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-localhost = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-localhost = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
portpicker = "0.1" # used in the example to pick a random free port portpicker = "0.1" # used in the example to pick a random free port
``` ```

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-log = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-log#next pnpm add https://github.com/tauri-apps/tauri-plugin-log#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-log#next npm add https://github.com/tauri-apps/tauri-plugin-log#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-log#next yarn add https://github.com/tauri-apps/tauri-plugin-log#v2
``` ```
## Usage ## Usage
@ -57,14 +57,14 @@ 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 ```javascript
import { trace, info, error, attachConsole } from 'tauri-plugin-log-api'; import { trace, info, error, attachConsole } from "tauri-plugin-log-api";
// with LogTarget::Webview enabled this function will print logs to the browser console // with LogTarget::Webview enabled this function will print logs to the browser console
const detach = await attachConsole(); const detach = await attachConsole();
trace('Trace'); trace("Trace");
info('Info'); info("Info");
error('Error'); error("Error");
// detach the browser console from the log stream // detach the browser console from the log stream
detach(); detach();

@ -52,10 +52,15 @@ async function log(
const { file, line, ...keyValues } = options ?? {}; const { file, line, ...keyValues } = options ?? {};
let location = filtered?.[0]?.filter((v) => v.length > 0).join("@");
if (location === "Error") {
location = "webview::unknown";
}
await invoke("plugin:log|log", { await invoke("plugin:log|log", {
level, level,
message, message,
location: filtered?.[0]?.filter((v) => v.length > 0).join("@"), location,
file, file,
line, line,
keyValues, keyValues,
@ -184,7 +189,8 @@ export async function attachConsole(): Promise<UnlistenFn> {
// Strip ANSI escape codes // Strip ANSI escape codes
const message = payload.message.replace( const message = payload.message.replace(
// eslint-disable-next-line no-control-regex // 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, /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g,
"" ""
); );

@ -178,8 +178,8 @@ fn log(
let location = location.unwrap_or("webview"); let location = location.unwrap_or("webview");
let mut builder = RecordBuilder::new(); let mut builder = RecordBuilder::new();
builder builder
.target(location)
.level(level.into()) .level(level.into())
.target(location)
.file(file) .file(file)
.line(line); .line(line);
@ -251,8 +251,8 @@ impl Builder {
out.finish(format_args!( out.finish(format_args!(
"{}[{}][{}] {}", "{}[{}][{}] {}",
timezone_strategy.get_now().format(&format).unwrap(), timezone_strategy.get_now().format(&format).unwrap(),
record.target(),
record.level(), record.level(),
record.target(),
message message
)) ))
}); });
@ -311,8 +311,8 @@ impl Builder {
out.finish(format_args!( out.finish(format_args!(
"{}[{}][{}] {}", "{}[{}][{}] {}",
timezone_strategy.get_now().format(&format).unwrap(), timezone_strategy.get_now().format(&format).unwrap(),
record.target(),
colors.color(record.level()), colors.color(record.level()),
record.target(),
message message
)) ))
}) })

@ -298,7 +298,7 @@ interface Channel {
} }
/** Possible permission values. */ /** Possible permission values. */
type Permission = 'granted' | 'denied' | 'default' type Permission = "granted" | "denied" | "default";
/** /**
* Checks if the permission to send notifications is granted. * Checks if the permission to send notifications is granted.
@ -311,10 +311,10 @@ type Permission = 'granted' | 'denied' | 'default'
* @since 1.0.0 * @since 1.0.0
*/ */
async function isPermissionGranted(): Promise<boolean> { async function isPermissionGranted(): Promise<boolean> {
if (window.Notification.permission !== 'default') { if (window.Notification.permission !== "default") {
return Promise.resolve(window.Notification.permission === 'granted') return Promise.resolve(window.Notification.permission === "granted");
} }
return invoke('plugin:notification|is_permission_granted') return invoke("plugin:notification|is_permission_granted");
} }
/** /**
@ -334,7 +334,7 @@ async function isPermissionGranted(): Promise<boolean> {
* @since 1.0.0 * @since 1.0.0
*/ */
async function requestPermission(): Promise<Permission> { async function requestPermission(): Promise<Permission> {
return window.Notification.requestPermission() return window.Notification.requestPermission();
} }
/** /**
@ -356,12 +356,12 @@ async function requestPermission(): Promise<Permission> {
* @since 1.0.0 * @since 1.0.0
*/ */
function sendNotification(options: Options | string): void { function sendNotification(options: Options | string): void {
if (typeof options === 'string') { if (typeof options === "string") {
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new window.Notification(options) new window.Notification(options);
} else { } else {
// eslint-disable-next-line no-new // eslint-disable-next-line no-new
new window.Notification(options.title, options) new window.Notification(options.title, options);
} }
} }

@ -1,71 +1,71 @@
(function () { (function () {
let permissionSettable = false let permissionSettable = false;
let permissionValue = 'default' let permissionValue = "default";
function isPermissionGranted() { function isPermissionGranted() {
if (window.Notification.permission !== 'default') { if (window.Notification.permission !== "default") {
return Promise.resolve(window.Notification.permission === 'granted') return Promise.resolve(window.Notification.permission === "granted");
} }
return __TAURI__.invoke('plugin:notification|is_permission_granted') return window.__TAURI__.invoke("plugin:notification|is_permission_granted");
} }
function setNotificationPermission(value) { function setNotificationPermission(value) {
permissionSettable = true permissionSettable = true;
// @ts-expect-error we can actually set this value on the webview // @ts-expect-error we can actually set this value on the webview
window.Notification.permission = value window.Notification.permission = value;
permissionSettable = false permissionSettable = false;
} }
function requestPermission() { function requestPermission() {
return __TAURI__.invoke('plugin:notification|request_permission') return window.__TAURI__
.invoke("plugin:notification|request_permission")
.then(function (permission) { .then(function (permission) {
setNotificationPermission(permission) setNotificationPermission(permission);
return permission return permission;
}) });
} }
function sendNotification(options) { function sendNotification(options) {
if (typeof options === 'object') { if (typeof options === "object") {
Object.freeze(options) Object.freeze(options);
} }
return __TAURI__.invoke('plugin:notification|notify', { return window.__TAURI__.invoke("plugin:notification|notify", {
options: typeof options === 'string' options:
? { typeof options === "string"
title: options ? {
} title: options,
: options }
}) : options,
});
} }
// @ts-expect-error unfortunately we can't implement the whole type, so we overwrite it with our own version // @ts-expect-error unfortunately we can't implement the whole type, so we overwrite it with our own version
window.Notification = function (title, options) { window.Notification = function (title, options) {
const opts = options || {} const opts = options || {};
sendNotification( sendNotification(Object.assign(opts, { title }));
Object.assign(opts, { title }) };
)
}
window.Notification.requestPermission = requestPermission window.Notification.requestPermission = requestPermission;
Object.defineProperty(window.Notification, 'permission', { Object.defineProperty(window.Notification, "permission", {
enumerable: true, enumerable: true,
get: function () { get: function () {
return permissionValue return permissionValue;
}, },
set: function (v) { set: function (v) {
if (!permissionSettable) { if (!permissionSettable) {
throw new Error('Readonly property') throw new Error("Readonly property");
} }
permissionValue = v permissionValue = v;
} },
}) });
isPermissionGranted().then(function (response) { isPermissionGranted().then(function (response) {
if (response === null) { if (response === null) {
setNotificationPermission('default') setNotificationPermission("default");
} else { } else {
setNotificationPermission(response ? 'granted' : 'denied') setNotificationPermission(response ? "granted" : "denied");
} }
}) });
})() })();

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-persisted-scope = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-persisted-scope = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
## Usage ## Usage

@ -22,7 +22,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
[dependencies] [dependencies]
tauri-plugin-positioner = "1.0" tauri-plugin-positioner = "1.0"
# or through git # or through git
tauri-plugin-positioner = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-positioner = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -30,21 +30,21 @@ 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. > 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 ```sh
pnpm add tauri-plugin-positioner pnpm add tauri-plugin-positioner-api
# or # or
npm add tauri-plugin-positioner npm add tauri-plugin-positioner-api
# or # or
yarn add tauri-plugin-positioner yarn add tauri-plugin-positioner-api
``` ```
Or through git: Or through git:
```sh ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-positioner#next pnpm add https://github.com/tauri-apps/tauri-plugin-positioner#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-positioner#next npm add https://github.com/tauri-apps/tauri-plugin-positioner#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-positioner#next yarn add https://github.com/tauri-apps/tauri-plugin-positioner#v2
``` ```
## Usage ## Usage
@ -69,7 +69,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 ```javascript
import { move_window, Position } from 'tauri-plugin-positioner-api'; import { move_window, Position } from "tauri-plugin-positioner-api";
move_window(Position.TopRight); move_window(Position.TopRight);
``` ```

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-shell = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-shell#next pnpm add https://github.com/tauri-apps/tauri-plugin-shell#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-shell#next npm add https://github.com/tauri-apps/tauri-plugin-shell#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-shell#next yarn add https://github.com/tauri-apps/tauri-plugin-shell#v2
``` ```
## Usage ## Usage

@ -75,27 +75,27 @@
* @module * @module
*/ */
import { invoke, transformCallback } from '@tauri-apps/api/tauri' import { invoke, transformCallback } from "@tauri-apps/api/tauri";
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
interface SpawnOptions { interface SpawnOptions {
/** Current working directory. */ /** Current working directory. */
cwd?: string cwd?: string;
/** Environment variables. set to `null` to clear the process env. */ /** Environment variables. set to `null` to clear the process env. */
env?: Record<string, string> env?: Record<string, string>;
/** /**
* Character encoding for stdout/stderr * Character encoding for stdout/stderr
* *
* @since 1.1.0 * @since 1.1.0
* */ * */
encoding?: string encoding?: string;
} }
/** @ignore */ /** @ignore */
interface InternalSpawnOptions extends SpawnOptions { interface InternalSpawnOptions extends SpawnOptions {
sidecar?: boolean sidecar?: boolean;
} }
/** /**
@ -103,13 +103,13 @@ interface InternalSpawnOptions extends SpawnOptions {
*/ */
interface ChildProcess<O extends IOPayload> { interface ChildProcess<O extends IOPayload> {
/** Exit code of the process. `null` if the process was terminated by a signal on Unix. */ /** Exit code of the process. `null` if the process was terminated by a signal on Unix. */
code: number | null code: number | null;
/** If the process was terminated by a signal, represents that signal. */ /** If the process was terminated by a signal, represents that signal. */
signal: number | null signal: number | null;
/** The data that the process wrote to `stdout`. */ /** The data that the process wrote to `stdout`. */
stdout: O stdout: O;
/** The data that the process wrote to `stderr`. */ /** The data that the process wrote to `stderr`. */
stderr: O stderr: O;
} }
/** /**
@ -128,26 +128,27 @@ async function execute<O extends IOPayload>(
args: string | string[] = [], args: string | string[] = [],
options?: InternalSpawnOptions options?: InternalSpawnOptions
): Promise<number> { ): Promise<number> {
if (typeof args === 'object') { if (typeof args === "object") {
Object.freeze(args) Object.freeze(args);
} }
return invoke<number>('plugin:shell|execute', { return invoke<number>("plugin:shell|execute", {
program, program,
args, args,
options, options,
onEventFn: transformCallback(onEvent) onEventFn: transformCallback(onEvent),
}) });
} }
/** /**
* @since 1.0.0 * @since 1.0.0
*/ */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
class EventEmitter<E extends Record<string, any>> { class EventEmitter<E extends Record<string, any>> {
/** @ignore */ /** @ignore */
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
private eventListeners: Record<keyof E, Array<(arg: any) => void>> = private eventListeners: Record<keyof E, Array<(arg: any) => void>> =
Object.create(null) Object.create(null);
/** /**
* Alias for `emitter.on(eventName, listener)`. * Alias for `emitter.on(eventName, listener)`.
@ -158,7 +159,7 @@ class EventEmitter<E extends Record<string, any>> {
eventName: N, eventName: N,
listener: (arg: E[typeof eventName]) => void listener: (arg: E[typeof eventName]) => void
): this { ): this {
return this.on(eventName, listener) return this.on(eventName, listener);
} }
/** /**
@ -170,7 +171,7 @@ class EventEmitter<E extends Record<string, any>> {
eventName: N, eventName: N,
listener: (arg: E[typeof eventName]) => void listener: (arg: E[typeof eventName]) => void
): this { ): this {
return this.off(eventName, listener) return this.off(eventName, listener);
} }
/** /**
@ -189,12 +190,12 @@ class EventEmitter<E extends Record<string, any>> {
): this { ): this {
if (eventName in this.eventListeners) { if (eventName in this.eventListeners) {
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
this.eventListeners[eventName].push(listener) this.eventListeners[eventName].push(listener);
} else { } else {
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
this.eventListeners[eventName] = [listener] this.eventListeners[eventName] = [listener];
} }
return this return this;
} }
/** /**
@ -210,11 +211,11 @@ class EventEmitter<E extends Record<string, any>> {
listener: (arg: E[typeof eventName]) => void listener: (arg: E[typeof eventName]) => void
): this { ): this {
const wrapper = (arg: E[typeof eventName]): void => { const wrapper = (arg: E[typeof eventName]): void => {
this.removeListener(eventName, wrapper) this.removeListener(eventName, wrapper);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
listener(arg) listener(arg);
} };
return this.addListener(eventName, wrapper) return this.addListener(eventName, wrapper);
} }
/** /**
@ -231,9 +232,9 @@ class EventEmitter<E extends Record<string, any>> {
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
this.eventListeners[eventName] = this.eventListeners[eventName].filter( this.eventListeners[eventName] = this.eventListeners[eventName].filter(
(l) => l !== listener (l) => l !== listener
) );
} }
return this return this;
} }
/** /**
@ -246,12 +247,12 @@ class EventEmitter<E extends Record<string, any>> {
removeAllListeners<N extends keyof E>(event?: N): this { removeAllListeners<N extends keyof E>(event?: N): this {
if (event) { if (event) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete,security/detect-object-injection // eslint-disable-next-line @typescript-eslint/no-dynamic-delete,security/detect-object-injection
delete this.eventListeners[event] delete this.eventListeners[event];
} else { } else {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
this.eventListeners = Object.create(null) this.eventListeners = Object.create(null);
} }
return this return this;
} }
/** /**
@ -264,12 +265,12 @@ class EventEmitter<E extends Record<string, any>> {
emit<N extends keyof E>(eventName: N, arg: E[typeof eventName]): boolean { emit<N extends keyof E>(eventName: N, arg: E[typeof eventName]): boolean {
if (eventName in this.eventListeners) { if (eventName in this.eventListeners) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,security/detect-object-injection // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,security/detect-object-injection
const listeners = this.eventListeners[eventName] const listeners = this.eventListeners[eventName];
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
for (const listener of listeners) listener(arg) for (const listener of listeners) listener(arg);
return true return true;
} }
return false return false;
} }
/** /**
@ -280,8 +281,8 @@ class EventEmitter<E extends Record<string, any>> {
listenerCount<N extends keyof E>(eventName: N): number { listenerCount<N extends keyof E>(eventName: N): number {
if (eventName in this.eventListeners) if (eventName in this.eventListeners)
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
return this.eventListeners[eventName].length return this.eventListeners[eventName].length;
return 0 return 0;
} }
/** /**
@ -300,12 +301,12 @@ class EventEmitter<E extends Record<string, any>> {
): this { ): this {
if (eventName in this.eventListeners) { if (eventName in this.eventListeners) {
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
this.eventListeners[eventName].unshift(listener) this.eventListeners[eventName].unshift(listener);
} else { } else {
// eslint-disable-next-line security/detect-object-injection // eslint-disable-next-line security/detect-object-injection
this.eventListeners[eventName] = [listener] this.eventListeners[eventName] = [listener];
} }
return this return this;
} }
/** /**
@ -320,12 +321,13 @@ class EventEmitter<E extends Record<string, any>> {
eventName: N, eventName: N,
listener: (arg: E[typeof eventName]) => void listener: (arg: E[typeof eventName]) => void
): this { ): this {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const wrapper = (arg: any): void => { const wrapper = (arg: any): void => {
this.removeListener(eventName, wrapper) this.removeListener(eventName, wrapper);
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
listener(arg) listener(arg);
} };
return this.prependListener(eventName, wrapper) return this.prependListener(eventName, wrapper);
} }
} }
@ -334,10 +336,10 @@ class EventEmitter<E extends Record<string, any>> {
*/ */
class Child { class Child {
/** The child process `pid`. */ /** The child process `pid`. */
pid: number pid: number;
constructor(pid: number) { constructor(pid: number) {
this.pid = pid this.pid = pid;
} }
/** /**
@ -356,11 +358,11 @@ class Child {
* @returns A promise indicating the success or failure of the operation. * @returns A promise indicating the success or failure of the operation.
*/ */
async write(data: IOPayload): Promise<void> { async write(data: IOPayload): Promise<void> {
return invoke('plugin:shell|stdin_write', { return invoke("plugin:shell|stdin_write", {
pid: this.pid, pid: this.pid,
// correctly serialize Uint8Arrays // correctly serialize Uint8Arrays
buffer: typeof data === 'string' ? data : Array.from(data) buffer: typeof data === "string" ? data : Array.from(data),
}) });
} }
/** /**
@ -369,20 +371,20 @@ class Child {
* @returns A promise indicating the success or failure of the operation. * @returns A promise indicating the success or failure of the operation.
*/ */
async kill(): Promise<void> { async kill(): Promise<void> {
return invoke('plugin:shell|kill', { return invoke("plugin:shell|kill", {
cmd: 'killChild', cmd: "killChild",
pid: this.pid pid: this.pid,
}) });
} }
} }
interface CommandEvents { interface CommandEvents {
close: TerminatedPayload close: TerminatedPayload;
error: string error: string;
} }
interface OutputEvents<O extends IOPayload> { interface OutputEvents<O extends IOPayload> {
data: O data: O;
} }
/** /**
@ -408,15 +410,15 @@ interface OutputEvents<O extends IOPayload> {
*/ */
class Command<O extends IOPayload> extends EventEmitter<CommandEvents> { class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
/** @ignore Program to execute. */ /** @ignore Program to execute. */
private readonly program: string private readonly program: string;
/** @ignore Program arguments */ /** @ignore Program arguments */
private readonly args: string[] private readonly args: string[];
/** @ignore Spawn options. */ /** @ignore Spawn options. */
private readonly options: InternalSpawnOptions private readonly options: InternalSpawnOptions;
/** Event emitter for the `stdout`. Emits the `data` event. */ /** Event emitter for the `stdout`. Emits the `data` event. */
readonly stdout = new EventEmitter<OutputEvents<O>>() readonly stdout = new EventEmitter<OutputEvents<O>>();
/** Event emitter for the `stderr`. Emits the `data` event. */ /** Event emitter for the `stderr`. Emits the `data` event. */
readonly stderr = new EventEmitter<OutputEvents<O>>() readonly stderr = new EventEmitter<OutputEvents<O>>();
/** /**
* @ignore * @ignore
@ -432,23 +434,23 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
args: string | string[] = [], args: string | string[] = [],
options?: SpawnOptions options?: SpawnOptions
) { ) {
super() super();
this.program = program this.program = program;
this.args = typeof args === 'string' ? [args] : args this.args = typeof args === "string" ? [args] : args;
this.options = options ?? {} this.options = options ?? {};
} }
static create(program: string, args?: string | string[]): Command<string> static create(program: string, args?: string | string[]): Command<string>;
static create( static create(
program: string, program: string,
args?: string | string[], args?: string | string[],
options?: SpawnOptions & { encoding: 'raw' } options?: SpawnOptions & { encoding: "raw" }
): Command<Uint8Array> ): Command<Uint8Array>;
static create( static create(
program: string, program: string,
args?: string | string[], args?: string | string[],
options?: SpawnOptions options?: SpawnOptions
): Command<string> ): Command<string>;
/** /**
* Creates a command to execute the given program. * Creates a command to execute the given program.
@ -467,20 +469,20 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
args: string | string[] = [], args: string | string[] = [],
options?: SpawnOptions options?: SpawnOptions
): Command<O> { ): Command<O> {
return new Command(program, args, options) return new Command(program, args, options);
} }
static sidecar(program: string, args?: string | string[]): Command<string> static sidecar(program: string, args?: string | string[]): Command<string>;
static sidecar( static sidecar(
program: string, program: string,
args?: string | string[], args?: string | string[],
options?: SpawnOptions & { encoding: 'raw' } options?: SpawnOptions & { encoding: "raw" }
): Command<Uint8Array> ): Command<Uint8Array>;
static sidecar( static sidecar(
program: string, program: string,
args?: string | string[], args?: string | string[],
options?: SpawnOptions options?: SpawnOptions
): Command<string> ): Command<string>;
/** /**
* Creates a command to execute the given sidecar program. * Creates a command to execute the given sidecar program.
@ -499,9 +501,9 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
args: string | string[] = [], args: string | string[] = [],
options?: SpawnOptions options?: SpawnOptions
): Command<O> { ): Command<O> {
const instance = new Command<O>(program, args, options) const instance = new Command<O>(program, args, options);
instance.options.sidecar = true instance.options.sidecar = true;
return instance return instance;
} }
/** /**
@ -513,24 +515,24 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
return execute<O>( return execute<O>(
(event) => { (event) => {
switch (event.event) { switch (event.event) {
case 'Error': case "Error":
this.emit('error', event.payload) this.emit("error", event.payload);
break break;
case 'Terminated': case "Terminated":
this.emit('close', event.payload) this.emit("close", event.payload);
break break;
case 'Stdout': case "Stdout":
this.stdout.emit('data', event.payload) this.stdout.emit("data", event.payload);
break break;
case 'Stderr': case "Stderr":
this.stderr.emit('data', event.payload) this.stderr.emit("data", event.payload);
break break;
} }
}, },
this.program, this.program,
this.args, this.args,
this.options this.options
).then((pid) => new Child(pid)) ).then((pid) => new Child(pid));
} }
/** /**
@ -549,38 +551,38 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
*/ */
async execute(): Promise<ChildProcess<O>> { async execute(): Promise<ChildProcess<O>> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this.on('error', reject) this.on("error", reject);
const stdout: O[] = [] const stdout: O[] = [];
const stderr: O[] = [] const stderr: O[] = [];
this.stdout.on('data', (line: O) => { this.stdout.on("data", (line: O) => {
stdout.push(line) stdout.push(line);
}) });
this.stderr.on('data', (line: O) => { this.stderr.on("data", (line: O) => {
stderr.push(line) stderr.push(line);
}) });
this.on('close', (payload: TerminatedPayload) => { this.on("close", (payload: TerminatedPayload) => {
resolve({ resolve({
code: payload.code, code: payload.code,
signal: payload.signal, signal: payload.signal,
stdout: this.collectOutput(stdout) as O, stdout: this.collectOutput(stdout) as O,
stderr: this.collectOutput(stderr) as O stderr: this.collectOutput(stderr) as O,
}) });
}) });
this.spawn().catch(reject) this.spawn().catch(reject);
}) });
} }
/** @ignore */ /** @ignore */
private collectOutput(events: O[]): string | Uint8Array { private collectOutput(events: O[]): string | Uint8Array {
if (this.options.encoding === 'raw') { if (this.options.encoding === "raw") {
return events.reduce<Uint8Array>((p, c) => { return events.reduce<Uint8Array>((p, c) => {
return new Uint8Array([...p, ...(c as Uint8Array), 10]) return new Uint8Array([...p, ...(c as Uint8Array), 10]);
}, new Uint8Array()) }, new Uint8Array());
} else { } else {
return events.join('\n') return events.join("\n");
} }
} }
} }
@ -589,8 +591,8 @@ class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
* Describes the event message received from the command. * Describes the event message received from the command.
*/ */
interface Event<T, V> { interface Event<T, V> {
event: T event: T;
payload: V payload: V;
} }
/** /**
@ -598,20 +600,20 @@ interface Event<T, V> {
*/ */
interface TerminatedPayload { interface TerminatedPayload {
/** Exit code of the process. `null` if the process was terminated by a signal on Unix. */ /** Exit code of the process. `null` if the process was terminated by a signal on Unix. */
code: number | null code: number | null;
/** If the process was terminated by a signal, represents that signal. */ /** If the process was terminated by a signal, represents that signal. */
signal: number | null signal: number | null;
} }
/** Event payload type */ /** Event payload type */
type IOPayload = string | Uint8Array type IOPayload = string | Uint8Array;
/** Events emitted by the child process. */ /** Events emitted by the child process. */
type CommandEvent<O extends IOPayload> = type CommandEvent<O extends IOPayload> =
| Event<'Stdout', O> | Event<"Stdout", O>
| Event<'Stderr', O> | Event<"Stderr", O>
| Event<'Terminated', TerminatedPayload> | Event<"Terminated", TerminatedPayload>
| Event<'Error', string> | Event<"Error", string>;
/** /**
* Opens a path or URL with the system's default app, * Opens a path or URL with the system's default app,
@ -640,18 +642,18 @@ type CommandEvent<O extends IOPayload> =
* @since 1.0.0 * @since 1.0.0
*/ */
async function open(path: string, openWith?: string): Promise<void> { async function open(path: string, openWith?: string): Promise<void> {
return invoke('plugin:shell|open', { return invoke("plugin:shell|open", {
path, path,
with: openWith with: openWith,
}) });
} }
export { Command, Child, EventEmitter, open } export { Command, Child, EventEmitter, open };
export type { export type {
IOPayload, IOPayload,
CommandEvents, CommandEvents,
TerminatedPayload, TerminatedPayload,
OutputEvents, OutputEvents,
ChildProcess, ChildProcess,
SpawnOptions SpawnOptions,
} };

@ -29,4 +29,4 @@
"dependencies": { "dependencies": {
"@tauri-apps/api": "^1.2.0" "@tauri-apps/api": "^1.2.0"
} }
} }

@ -480,7 +480,7 @@ mod tests {
#[test] #[test]
fn test_cmd_output_output() { fn test_cmd_output_output() {
let cmd = Command::new("cat").args(["test/api/test.txt"]); let cmd = Command::new("cat").args(["test/api/test.txt"]);
let output = cmd.output().unwrap(); let output = tauri::async_runtime::block_on(cmd.output()).unwrap();
assert_eq!(String::from_utf8(output.stderr).unwrap(), ""); assert_eq!(String::from_utf8(output.stderr).unwrap(), "");
assert_eq!( assert_eq!(
@ -493,7 +493,7 @@ mod tests {
#[test] #[test]
fn test_cmd_output_output_fail() { fn test_cmd_output_output_fail() {
let cmd = Command::new("cat").args(["test/api/"]); let cmd = Command::new("cat").args(["test/api/"]);
let output = cmd.output().unwrap(); let output = tauri::async_runtime::block_on(cmd.output()).unwrap();
assert_eq!(String::from_utf8(output.stdout).unwrap(), ""); assert_eq!(String::from_utf8(output.stdout).unwrap(), "");
assert_eq!( assert_eq!(

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-single-instance = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
## Usage ## Usage

@ -19,7 +19,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies.tauri-plugin-sql] [dependencies.tauri-plugin-sql]
git = "https://github.com/tauri-apps/plugins-workspace" git = "https://github.com/tauri-apps/plugins-workspace"
branch = "next" branch = "v2"
features = ["sqlite"] # or "postgres", or "mysql" features = ["sqlite"] # or "postgres", or "mysql"
``` ```
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-sql#next pnpm add https://github.com/tauri-apps/tauri-plugin-sql#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-sql#next npm add https://github.com/tauri-apps/tauri-plugin-sql#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-sql#next yarn add https://github.com/tauri-apps/tauri-plugin-sql#v2
``` ```
## Usage ## Usage
@ -53,16 +53,16 @@ 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 ```javascript
import Database from 'tauri-plugin-sql-api'; import Database from "tauri-plugin-sql-api";
// sqlite. The path is relative to `tauri::api::path::BaseDirectory::App`. // sqlite. The path is relative to `tauri::api::path::BaseDirectory::App`.
const db = await Database.load('sqlite:test.db'); const db = await Database.load("sqlite:test.db");
// mysql // mysql
const db = await Database.load('mysql://user:pass@host/database'); const db = await Database.load("mysql://user:pass@host/database");
// postgres // postgres
const db = await Database.load('postgres://postgres:password@localhost/test'); const db = await Database.load("postgres://postgres:password@localhost/test");
await db.execute('INSERT INTO ...'); await db.execute("INSERT INTO ...");
``` ```
## Contributing ## Contributing

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-store = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-store#next pnpm add https://github.com/tauri-apps/tauri-plugin-store#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-store#next npm add https://github.com/tauri-apps/tauri-plugin-store#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-store#next yarn add https://github.com/tauri-apps/tauri-plugin-store#v2
``` ```
## Usage ## Usage
@ -51,13 +51,13 @@ 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 ```javascript
import { Store } from 'tauri-plugin-store-api'; import { Store } from "tauri-plugin-store-api";
const store = new Store('.settings.dat'); const store = new Store(".settings.dat");
await store.set('some-key', { value: 5 }); await store.set("some-key", { value: 5 });
const val = await store.get('some-key'); const val = await store.get("some-key");
assert(val, { value: 5 }); assert(val, { value: 5 });
await store.save(); // this manually saves the store, otherwise the store is only saved when your app is closed await store.save(); // this manually saves the store, otherwise the store is only saved when your app is closed

@ -175,8 +175,9 @@ pub struct Store<R: Runtime> {
impl<R: Runtime> Store<R> { impl<R: Runtime> Store<R> {
/// Update the store from the on-disk state /// Update the store from the on-disk state
pub fn load<R: Runtime>(&mut self, app: &AppHandle<R>) -> Result<(), Error> { pub fn load(&mut self) -> Result<(), Error> {
let app_dir = app let app_dir = self
.app
.path() .path()
.app_data_dir() .app_data_dir()
.expect("failed to resolve app dir"); .expect("failed to resolve app dir");
@ -191,8 +192,9 @@ impl<R: Runtime> Store<R> {
} }
/// Saves the store to disk /// Saves the store to disk
pub fn save<R: Runtime>(&self, app: &AppHandle<R>) -> Result<(), Error> { pub fn save(&self) -> Result<(), Error> {
let app_dir = app let app_dir = self
.app
.path() .path()
.app_data_dir() .app_data_dir()
.expect("failed to resolve app dir"); .expect("failed to resolve app dir");

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-stronghold = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-stronghold = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-stronghold#next pnpm add https://github.com/tauri-apps/tauri-plugin-stronghold#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-stronghold#next npm add https://github.com/tauri-apps/tauri-plugin-stronghold#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-stronghold#next yarn add https://github.com/tauri-apps/tauri-plugin-stronghold#v2
``` ```
## Usage ## Usage
@ -55,7 +55,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 ```javascript
import { Stronghold, Location } from 'tauri-plugin-stronghold-api'; import { Stronghold, Location } from "tauri-plugin-stronghold-api";
// TODO // TODO
``` ```

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-upload = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-upload = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-upload#next pnpm add https://github.com/tauri-apps/tauri-plugin-upload#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-upload#next npm add https://github.com/tauri-apps/tauri-plugin-upload#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-upload#next yarn add https://github.com/tauri-apps/tauri-plugin-upload#v2
``` ```
## Usage ## Usage

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-websocket = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-websocket = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-websocket#next pnpm add https://github.com/tauri-apps/tauri-plugin-websocket#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-websocket#next npm add https://github.com/tauri-apps/tauri-plugin-websocket#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-websocket#next yarn add https://github.com/tauri-apps/tauri-plugin-websocket#v2
``` ```
## Usage ## Usage
@ -51,11 +51,11 @@ 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 ```javascript
import { WebSocket } from 'tauri-plugin-websocket-api'; import { WebSocket } from "tauri-plugin-websocket-api";
const ws = await WebSocket.connect('wss://example.com'); const ws = await WebSocket.connect("wss://example.com");
await ws.send('Hello World'); await ws.send("Hello World");
await ws.disconnect(); await ws.disconnect();
``` ```

@ -79,15 +79,14 @@ enum WebSocketMessage {
} }
#[tauri::command] #[tauri::command]
fn connect<R: Runtime>( async fn connect<R: Runtime>(
window: Window<R>, window: Window<R>,
url: String, url: String,
callback_function: CallbackFn, callback_function: CallbackFn,
config: Option<ConnectionConfig>, config: Option<ConnectionConfig>,
) -> Result<Id> { ) -> Result<Id> {
let id = rand::random(); let id = rand::random();
let (ws_stream, _) = let (ws_stream, _) = connect_async_with_config(url, config.map(Into::into)).await?;
tauri::async_runtime::block_on(connect_async_with_config(url, config.map(Into::into)))?;
tauri::async_runtime::spawn(async move { tauri::async_runtime::spawn(async move {
let (write, read) = ws_stream.split(); let (write, read) = ws_stream.split();

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "next" } tauri-plugin-window-state = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:
@ -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. > 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 ```sh
pnpm add https://github.com/tauri-apps/tauri-plugin-window-state#next pnpm add https://github.com/tauri-apps/tauri-plugin-window-state#v2
# or # or
npm add https://github.com/tauri-apps/tauri-plugin-window-state#next npm add https://github.com/tauri-apps/tauri-plugin-window-state#v2
# or # or
yarn add https://github.com/tauri-apps/tauri-plugin-window-state#next yarn add https://github.com/tauri-apps/tauri-plugin-window-state#v2
``` ```
## Usage ## Usage
@ -62,7 +62,7 @@ app.save_window_state(StateFlags::all()); // will save the state of all open win
or through Javascript or through Javascript
```javascript ```javascript
import { saveWindowState, StateFlags } from 'tauri-plugin-window-state-api'; import { saveWindowState, StateFlags } from "tauri-plugin-window-state-api";
saveWindowState(StateFlags.ALL); saveWindowState(StateFlags.ALL);
``` ```
@ -79,7 +79,7 @@ window.restore_state(StateFlags::all()); // will restore the windows state from
or through Javascript or through Javascript
```javascript ```javascript
import { restoreStateCurrent, StateFlags } from 'tauri-plugin-window-state-api'; import { restoreStateCurrent, StateFlags } from "tauri-plugin-window-state-api";
restoreStateCurrent(StateFlags.ALL); restoreStateCurrent(StateFlags.ALL);
``` ```

@ -37,6 +37,9 @@ importers:
eslint-plugin-promise: eslint-plugin-promise:
specifier: ^6.1.1 specifier: ^6.1.1
version: 6.1.1(eslint@8.39.0) version: 6.1.1(eslint@8.39.0)
eslint-plugin-security:
specifier: ^1.7.1
version: 1.7.1
prettier: prettier:
specifier: ^2.8.7 specifier: ^2.8.7
version: 2.8.8 version: 2.8.8
@ -1758,6 +1761,12 @@ packages:
eslint: 8.39.0 eslint: 8.39.0
dev: true dev: true
/eslint-plugin-security@1.7.1:
resolution: {integrity: sha512-sMStceig8AFglhhT2LqlU5r+/fn9OwsA72O5bBuQVTssPCdQAOQzL+oMn/ZcpeUY6KcNfLJArgcrsSULNjYYdQ==}
dependencies:
safe-regex: 2.1.1
dev: true
/eslint-scope@5.1.1: /eslint-scope@5.1.1:
resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==}
engines: {node: '>=8.0.0'} engines: {node: '>=8.0.0'}
@ -2686,6 +2695,11 @@ packages:
picomatch: 2.3.1 picomatch: 2.3.1
dev: true dev: true
/regexp-tree@0.1.27:
resolution: {integrity: sha512-iETxpjK6YoRWJG5o6hXLwvjYAoW+FEZn9os0PD/b6AP6xQwsa/Y7lCVgIixBbUPMfhu+i2LtdeAqVTgGlQarfA==}
hasBin: true
dev: true
/regexp.prototype.flags@1.4.3: /regexp.prototype.flags@1.4.3:
resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==} resolution: {integrity: sha512-fjggEOO3slI6Wvgjwflkc4NFRCTZAu5CnNfBd5qOMYhWdn67nJBBu34/TkD++eeFmd8C9r9jfXJ27+nSiRkSUA==}
engines: {node: '>= 0.4'} engines: {node: '>= 0.4'}
@ -2774,6 +2788,12 @@ packages:
is-regex: 1.1.4 is-regex: 1.1.4
dev: true dev: true
/safe-regex@2.1.1:
resolution: {integrity: sha512-rx+x8AMzKb5Q5lQ95Zoi6ZbJqwCLkqi3XuJXp5P3rT8OEc6sZCJG5AE5dU3lsgRr/F4Bs31jSlVN+j5KrsGu9A==}
dependencies:
regexp-tree: 0.1.27
dev: true
/sander@0.5.1: /sander@0.5.1:
resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==}
dependencies: dependencies:

@ -18,7 +18,7 @@ Install the Core plugin by adding the following to your `Cargo.toml` file:
```toml ```toml
[dependencies] [dependencies]
<!-- plugin here --> = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "dev" } <!-- plugin here --> = { git = "https://github.com/tauri-apps/plugins-workspace", branch = "v2" }
``` ```
You can install the JavaScript Guest bindings using your preferred JavaScript package manager: You can install the JavaScript Guest bindings using your preferred JavaScript package manager:

@ -1,20 +1,20 @@
{ {
"compilerOptions": { "compilerOptions": {
"allowSyntheticDefaultImports": true, "allowSyntheticDefaultImports": true,
"esModuleInterop": true, "esModuleInterop": true,
"lib": ["ES2019", "ES2020.Promise", "ES2020.String", "DOM", "DOM.Iterable"], "lib": ["ES2019", "ES2020.Promise", "ES2020.String", "DOM", "DOM.Iterable"],
"module": "ESNext", "module": "ESNext",
"moduleResolution": "node", "moduleResolution": "node",
"noEmit": true, "noEmit": true,
"noEmitOnError": false, "noEmitOnError": false,
"noUnusedLocals": true, "noUnusedLocals": true,
"noUnusedParameters": true, "noUnusedParameters": true,
"pretty": true, "pretty": true,
"sourceMap": true, "sourceMap": true,
"strict": true, "strict": true,
"target": "ES2019", "target": "ES2019",
"declaration": true, "declaration": true,
"declarationDir": "./" "declarationDir": "./"
}, },
"exclude": ["dist-js", "node_modules", "test/types"] "exclude": ["dist-js", "node_modules", "test/types"]
} }

Loading…
Cancel
Save