feat: add Tauri desktop chat app with React + TypeScript
This commit is contained in:
1 parent
d8c5697f39
commit
ee3980436b
4132 files changed
+1163398
No files matched your search
+20
@@ -0,0 +1,20 @@
|
||||
SPDXVersion: SPDX-2.1
|
||||
DataLicense: CC0-1.0
|
||||
PackageName: tauri
|
||||
DataFormat: SPDXRef-1
|
||||
PackageSupplier: Organization: The Tauri Programme in the Commons Conservancy
|
||||
PackageHomePage: https://tauri.app
|
||||
PackageLicenseDeclared: Apache-2.0
|
||||
PackageLicenseDeclared: MIT
|
||||
PackageCopyrightText: 2019-2022, The Tauri Programme in the Commons Conservancy
|
||||
PackageSummary: <text>Tauri is a rust project that enables developers to make secure
|
||||
and small desktop applications using a web frontend.
|
||||
</text>
|
||||
PackageComment: <text>The package includes the following libraries; see
|
||||
Relationship information.
|
||||
</text>
|
||||
Created: 2019-05-20T09:00:00Z
|
||||
PackageDownloadLocation: git://github.com/tauri-apps/tauri
|
||||
PackageDownloadLocation: git+https://github.com/tauri-apps/tauri.git
|
||||
PackageDownloadLocation: git+ssh://github.com/tauri-apps/tauri.git
|
||||
Creator: Person: Daniel Thompson-Yvetot
|
||||
+90
@@ -0,0 +1,90 @@
|
||||

|
||||
|
||||
Access the system shell. Allows you to spawn child processes and manage files and URLs using their default application.
|
||||
|
||||
| Platform | Supported |
|
||||
| -------- | --------- |
|
||||
| Linux | ✓ |
|
||||
| Windows | ✓ |
|
||||
| macOS | ✓ |
|
||||
| Android | ✓ |
|
||||
| iOS | ✓ |
|
||||
|
||||
## Install
|
||||
|
||||
_This plugin requires a Rust version of at least **1.77.2**_
|
||||
|
||||
There are three general methods of installation that we can recommend.
|
||||
|
||||
1. Use crates.io and npm (easiest, and requires you to trust that our publishing pipeline worked)
|
||||
2. Pull sources directly from Github using git tags / revision hashes (most secure)
|
||||
3. Git submodule install this repo in your tauri project and then use file protocol to ingest the source (most secure, but inconvenient to use)
|
||||
|
||||
Install the Core plugin by adding the following to your `Cargo.toml` file:
|
||||
|
||||
`src-tauri/Cargo.toml`
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
tauri-plugin-shell = "2.0.0"
|
||||
# alternatively with Git:
|
||||
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:
|
||||
|
||||
```sh
|
||||
pnpm add @tauri-apps/plugin-shell
|
||||
# or
|
||||
npm add @tauri-apps/plugin-shell
|
||||
# or
|
||||
yarn add @tauri-apps/plugin-shell
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First you need to register the core plugin with Tauri:
|
||||
|
||||
`src-tauri/src/lib.rs`
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
tauri::Builder::default()
|
||||
.plugin(tauri_plugin_shell::init())
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
}
|
||||
```
|
||||
|
||||
Afterwards all the plugin's APIs are available through the JavaScript guest bindings:
|
||||
|
||||
```javascript
|
||||
import { Command } from '@tauri-apps/plugin-shell'
|
||||
Command.create('git', ['commit', '-m', 'the commit message'])
|
||||
```
|
||||
|
||||
## Contributing
|
||||
|
||||
PRs accepted. Please make sure to read the Contributing Guide before making a pull request.
|
||||
|
||||
## Partners
|
||||
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://crabnebula.dev" target="_blank">
|
||||
<img src="https://github.com/tauri-apps/plugins-workspace/raw/v2/.github/sponsors/crabnebula.svg" alt="CrabNebula" width="283">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
For the complete list of sponsors please visit our [website](https://tauri.app#sponsors) and [Open Collective](https://opencollective.com/tauri).
|
||||
|
||||
## License
|
||||
|
||||
Code: (c) 2015 - Present - The Tauri Programme within The Commons Conservancy.
|
||||
|
||||
MIT or MIT/Apache 2.0 where applicable.
|
||||
+451
@@ -0,0 +1,451 @@
|
||||
'use strict';
|
||||
|
||||
var core = require('@tauri-apps/api/core');
|
||||
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
* Access the system shell.
|
||||
* Allows you to spawn child processes and manage files and URLs using their default application.
|
||||
*
|
||||
* ## Security
|
||||
*
|
||||
* This API has a scope configuration that forces you to restrict the programs and arguments that can be used.
|
||||
*
|
||||
* ### Restricting access to the {@link open | `open`} API
|
||||
*
|
||||
* On the configuration object, `open: true` means that the {@link open} API can be used with any URL,
|
||||
* as the argument is validated with the `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+` regex.
|
||||
* You can change that regex by changing the boolean value to a string, e.g. `open: ^https://github.com/`.
|
||||
*
|
||||
* ### Restricting access to the {@link Command | `Command`} APIs
|
||||
*
|
||||
* The plugin permissions object has a `scope` field that defines an array of CLIs that can be used.
|
||||
* Each CLI is a configuration object `{ name: string, cmd: string, sidecar?: bool, args?: boolean | Arg[] }`.
|
||||
*
|
||||
* - `name`: the unique identifier of the command, passed to the {@link Command.create | Command.create function}.
|
||||
* If it's a sidecar, this must be the value defined on `tauri.conf.json > bundle > externalBin`.
|
||||
* - `cmd`: the program that is executed on this configuration. If it's a sidecar, this value is ignored.
|
||||
* - `sidecar`: whether the object configures a sidecar or a system program.
|
||||
* - `args`: the arguments that can be passed to the program. By default no arguments are allowed.
|
||||
* - `true` means that any argument list is allowed.
|
||||
* - `false` means that no arguments are allowed.
|
||||
* - otherwise an array can be configured. Each item is either a string representing the fixed argument value
|
||||
* or a `{ validator: string }` that defines a regex validating the argument value.
|
||||
*
|
||||
* #### Example scope configuration
|
||||
*
|
||||
* CLI: `git commit -m "the commit message"`
|
||||
*
|
||||
* Capability:
|
||||
* ```json
|
||||
* {
|
||||
* "permissions": [
|
||||
* {
|
||||
* "identifier": "shell:allow-execute",
|
||||
* "allow": [
|
||||
* {
|
||||
* "name": "run-git-commit",
|
||||
* "cmd": "git",
|
||||
* "args": ["commit", "-m", { "validator": "\\S+" }]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ```
|
||||
* Usage:
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell'
|
||||
* Command.create('run-git-commit', ['commit', '-m', 'the commit message'])
|
||||
* ```
|
||||
*
|
||||
* Trying to execute any API with a program not configured on the scope results in a promise rejection due to denied access.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
class EventEmitter {
|
||||
constructor() {
|
||||
/** @ignore */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
||||
this.eventListeners = Object.create(null);
|
||||
}
|
||||
/**
|
||||
* Alias for `emitter.on(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
addListener(eventName, listener) {
|
||||
return this.on(eventName, listener);
|
||||
}
|
||||
/**
|
||||
* Alias for `emitter.off(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeListener(eventName, listener) {
|
||||
return this.off(eventName, listener);
|
||||
}
|
||||
/**
|
||||
* Adds the `listener` function to the end of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
on(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName].push(listener);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName`. The
|
||||
* next time `eventName` is triggered, this listener is removed and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
once(eventName, listener) {
|
||||
const wrapper = (arg) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
listener(arg);
|
||||
};
|
||||
return this.addListener(eventName, wrapper);
|
||||
}
|
||||
/**
|
||||
* Removes the all specified listener from the listener array for the event eventName
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
off(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = this.eventListeners[eventName].filter((l) => l !== listener);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Removes all listeners, or those of the specified eventName.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeAllListeners(event) {
|
||||
if (event) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
delete this.eventListeners[event];
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.eventListeners = Object.create(null);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
* Synchronously calls each of the listeners registered for the event named`eventName`, in the order they were registered, passing the supplied arguments
|
||||
* to each.
|
||||
*
|
||||
* @returns `true` if the event had listeners, `false` otherwise.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
emit(eventName, arg) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
const listeners = this.eventListeners[eventName];
|
||||
for (const listener of listeners)
|
||||
listener(arg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the number of listeners listening to the event named `eventName`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
listenerCount(eventName) {
|
||||
if (eventName in this.eventListeners)
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
return this.eventListeners[eventName].length;
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Adds the `listener` function to the _beginning_ of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependListener(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName].unshift(listener);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName` to the_beginning_ of the listeners array. The next time `eventName` is triggered, this
|
||||
* listener is removed, and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependOnceListener(eventName, listener) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const wrapper = (arg) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
listener(arg);
|
||||
};
|
||||
return this.prependListener(eventName, wrapper);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Child {
|
||||
constructor(pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
/**
|
||||
* Writes `data` to the `stdin`.
|
||||
*
|
||||
* @param data The message to write, either a string or a byte array.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* const child = await command.spawn();
|
||||
* await child.write('message');
|
||||
* await child.write([0, 1, 2, 3, 4, 5]);
|
||||
* ```
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async write(data) {
|
||||
await core.invoke('plugin:shell|stdin_write', {
|
||||
pid: this.pid,
|
||||
buffer: data
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Kills the child process.
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async kill() {
|
||||
await core.invoke('plugin:shell|kill', {
|
||||
cmd: 'killChild',
|
||||
pid: this.pid
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The entry point for spawning child processes.
|
||||
* It emits the `close` and `error` events.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* command.on('close', data => {
|
||||
* console.log(`command finished with code ${data.code} and signal ${data.signal}`)
|
||||
* });
|
||||
* command.on('error', error => console.error(`command error: "${error}"`));
|
||||
* command.stdout.on('data', line => console.log(`command stdout: "${line}"`));
|
||||
* command.stderr.on('data', line => console.log(`command stderr: "${line}"`));
|
||||
*
|
||||
* const child = await command.spawn();
|
||||
* console.log('pid:', child.pid);
|
||||
* ```
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
*/
|
||||
class Command extends EventEmitter {
|
||||
/**
|
||||
* @ignore
|
||||
* Creates a new `Command` instance.
|
||||
*
|
||||
* @param program The program name to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
* @param args Program arguments.
|
||||
* @param options Spawn options.
|
||||
*/
|
||||
constructor(program, args = [], options) {
|
||||
super();
|
||||
/** Event emitter for the `stdout`. Emits the `data` event. */
|
||||
this.stdout = new EventEmitter();
|
||||
/** Event emitter for the `stderr`. Emits the `data` event. */
|
||||
this.stderr = new EventEmitter();
|
||||
this.program = program;
|
||||
this.args = typeof args === 'string' ? [args] : args;
|
||||
this.options = options ?? {};
|
||||
}
|
||||
/**
|
||||
* Creates a command to execute the given program.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('my-app', ['run', 'tauri']);
|
||||
* const output = await command.execute();
|
||||
* ```
|
||||
*
|
||||
* @param program The program to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
*/
|
||||
static create(program, args = [], options) {
|
||||
return new Command(program, args, options);
|
||||
}
|
||||
/**
|
||||
* Creates a command to execute the given sidecar program.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.sidecar('my-sidecar');
|
||||
* const output = await command.execute();
|
||||
* ```
|
||||
*
|
||||
* @param program The program to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
*/
|
||||
static sidecar(program, args = [], options) {
|
||||
const instance = new Command(program, args, options);
|
||||
instance.options.sidecar = true;
|
||||
return instance;
|
||||
}
|
||||
/**
|
||||
* Executes the command as a child process, returning a handle to it.
|
||||
*
|
||||
* @returns A promise resolving to the child process handle.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async spawn() {
|
||||
const program = this.program;
|
||||
const args = this.args;
|
||||
const options = this.options;
|
||||
if (typeof args === 'object') {
|
||||
Object.freeze(args);
|
||||
}
|
||||
const onEvent = new core.Channel();
|
||||
onEvent.onmessage = (event) => {
|
||||
switch (event.event) {
|
||||
case 'Error':
|
||||
this.emit('error', event.payload);
|
||||
break;
|
||||
case 'Terminated':
|
||||
this.emit('close', event.payload);
|
||||
break;
|
||||
case 'Stdout':
|
||||
this.stdout.emit('data', event.payload);
|
||||
break;
|
||||
case 'Stderr':
|
||||
this.stderr.emit('data', event.payload);
|
||||
break;
|
||||
}
|
||||
};
|
||||
return await core.invoke('plugin:shell|spawn', {
|
||||
program,
|
||||
args,
|
||||
options,
|
||||
onEvent
|
||||
}).then((pid) => new Child(pid));
|
||||
}
|
||||
/**
|
||||
* Executes the command as a child process, waiting for it to finish and collecting all of its output.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const output = await Command.create('echo', 'message').execute();
|
||||
* assert(output.code === 0);
|
||||
* assert(output.signal === null);
|
||||
* assert(output.stdout === 'message');
|
||||
* assert(output.stderr === '');
|
||||
* ```
|
||||
*
|
||||
* @returns A promise resolving to the child process output.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async execute() {
|
||||
const program = this.program;
|
||||
const args = this.args;
|
||||
const options = this.options;
|
||||
if (typeof args === 'object') {
|
||||
Object.freeze(args);
|
||||
}
|
||||
return await core.invoke('plugin:shell|execute', {
|
||||
program,
|
||||
args,
|
||||
options
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Opens a path or URL with the system's default app,
|
||||
* or the one specified with `openWith`.
|
||||
*
|
||||
* The `openWith` value must be one of `firefox`, `google chrome`, `chromium` `safari`,
|
||||
* `open`, `start`, `xdg-open`, `gio`, `gnome-open`, `kde-open` or `wslview`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { open } from '@tauri-apps/plugin-shell';
|
||||
* // opens the given URL on the default browser:
|
||||
* await open('https://github.com/tauri-apps/tauri');
|
||||
* // opens the given URL using `firefox`:
|
||||
* await open('https://github.com/tauri-apps/tauri', 'firefox');
|
||||
* // opens a file using the default program:
|
||||
* await open('/path/to/file');
|
||||
* ```
|
||||
*
|
||||
* @param path The path or URL to open.
|
||||
* This value is matched against the string regex defined on `tauri.conf.json > plugins > shell > open`,
|
||||
* which defaults to `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`.
|
||||
* @param openWith The app to open the file or URL with.
|
||||
* Defaults to the system default application for the specified path type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async function open(path, openWith) {
|
||||
await core.invoke('plugin:shell|open', {
|
||||
path,
|
||||
with: openWith
|
||||
});
|
||||
}
|
||||
|
||||
exports.Child = Child;
|
||||
exports.Command = Command;
|
||||
exports.EventEmitter = EventEmitter;
|
||||
exports.open = open;
|
||||
+277
@@ -0,0 +1,277 @@
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
interface SpawnOptions {
|
||||
/** Current working directory. */
|
||||
cwd?: string;
|
||||
/** Environment variables. set to `null` to clear the process env. */
|
||||
env?: Record<string, string>;
|
||||
/**
|
||||
* Character encoding for stdout/stderr
|
||||
*
|
||||
* @since 2.0.0
|
||||
* */
|
||||
encoding?: string;
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
interface ChildProcess<O extends IOPayload> {
|
||||
/** Exit code of the process. `null` if the process was terminated by a signal on Unix. */
|
||||
code: number | null;
|
||||
/** If the process was terminated by a signal, represents that signal. */
|
||||
signal: number | null;
|
||||
/** The data that the process wrote to `stdout`. */
|
||||
stdout: O;
|
||||
/** The data that the process wrote to `stderr`. */
|
||||
stderr: O;
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
declare class EventEmitter<E extends Record<string, any>> {
|
||||
/** @ignore */
|
||||
private eventListeners;
|
||||
/**
|
||||
* Alias for `emitter.on(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
addListener<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Alias for `emitter.off(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeListener<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Adds the `listener` function to the end of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
on<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName`. The
|
||||
* next time `eventName` is triggered, this listener is removed and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
once<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Removes the all specified listener from the listener array for the event eventName
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
off<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Removes all listeners, or those of the specified eventName.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeAllListeners<N extends keyof E>(event?: N): this;
|
||||
/**
|
||||
* @ignore
|
||||
* Synchronously calls each of the listeners registered for the event named`eventName`, in the order they were registered, passing the supplied arguments
|
||||
* to each.
|
||||
*
|
||||
* @returns `true` if the event had listeners, `false` otherwise.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
emit<N extends keyof E>(eventName: N, arg: E[typeof eventName]): boolean;
|
||||
/**
|
||||
* Returns the number of listeners listening to the event named `eventName`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
listenerCount<N extends keyof E>(eventName: N): number;
|
||||
/**
|
||||
* Adds the `listener` function to the _beginning_ of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependListener<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName` to the_beginning_ of the listeners array. The next time `eventName` is triggered, this
|
||||
* listener is removed, and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependOnceListener<N extends keyof E>(eventName: N, listener: (arg: E[typeof eventName]) => void): this;
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
declare class Child {
|
||||
/** The child process `pid`. */
|
||||
pid: number;
|
||||
constructor(pid: number);
|
||||
/**
|
||||
* Writes `data` to the `stdin`.
|
||||
*
|
||||
* @param data The message to write, either a string or a byte array.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* const child = await command.spawn();
|
||||
* await child.write('message');
|
||||
* await child.write([0, 1, 2, 3, 4, 5]);
|
||||
* ```
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
write(data: IOPayload | number[]): Promise<void>;
|
||||
/**
|
||||
* Kills the child process.
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
kill(): Promise<void>;
|
||||
}
|
||||
interface CommandEvents {
|
||||
close: TerminatedPayload;
|
||||
error: string;
|
||||
}
|
||||
interface OutputEvents<O extends IOPayload> {
|
||||
data: O;
|
||||
}
|
||||
/**
|
||||
* The entry point for spawning child processes.
|
||||
* It emits the `close` and `error` events.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* command.on('close', data => {
|
||||
* console.log(`command finished with code ${data.code} and signal ${data.signal}`)
|
||||
* });
|
||||
* command.on('error', error => console.error(`command error: "${error}"`));
|
||||
* command.stdout.on('data', line => console.log(`command stdout: "${line}"`));
|
||||
* command.stderr.on('data', line => console.log(`command stderr: "${line}"`));
|
||||
*
|
||||
* const child = await command.spawn();
|
||||
* console.log('pid:', child.pid);
|
||||
* ```
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
*/
|
||||
declare class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
|
||||
/** @ignore Program to execute. */
|
||||
private readonly program;
|
||||
/** @ignore Program arguments */
|
||||
private readonly args;
|
||||
/** @ignore Spawn options. */
|
||||
private readonly options;
|
||||
/** Event emitter for the `stdout`. Emits the `data` event. */
|
||||
readonly stdout: EventEmitter<OutputEvents<O>>;
|
||||
/** Event emitter for the `stderr`. Emits the `data` event. */
|
||||
readonly stderr: EventEmitter<OutputEvents<O>>;
|
||||
/**
|
||||
* @ignore
|
||||
* Creates a new `Command` instance.
|
||||
*
|
||||
* @param program The program name to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
* @param args Program arguments.
|
||||
* @param options Spawn options.
|
||||
*/
|
||||
private constructor();
|
||||
static create(program: string, args?: string | string[]): Command<string>;
|
||||
static create(program: string, args?: string | string[], options?: SpawnOptions & {
|
||||
encoding: 'raw';
|
||||
}): Command<Uint8Array>;
|
||||
static create(program: string, args?: string | string[], options?: SpawnOptions): Command<string>;
|
||||
static sidecar(program: string, args?: string | string[]): Command<string>;
|
||||
static sidecar(program: string, args?: string | string[], options?: SpawnOptions & {
|
||||
encoding: 'raw';
|
||||
}): Command<Uint8Array>;
|
||||
static sidecar(program: string, args?: string | string[], options?: SpawnOptions): Command<string>;
|
||||
/**
|
||||
* Executes the command as a child process, returning a handle to it.
|
||||
*
|
||||
* @returns A promise resolving to the child process handle.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
spawn(): Promise<Child>;
|
||||
/**
|
||||
* Executes the command as a child process, waiting for it to finish and collecting all of its output.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const output = await Command.create('echo', 'message').execute();
|
||||
* assert(output.code === 0);
|
||||
* assert(output.signal === null);
|
||||
* assert(output.stdout === 'message');
|
||||
* assert(output.stderr === '');
|
||||
* ```
|
||||
*
|
||||
* @returns A promise resolving to the child process output.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
execute(): Promise<ChildProcess<O>>;
|
||||
}
|
||||
/**
|
||||
* Payload for the `Terminated` command event.
|
||||
*/
|
||||
interface TerminatedPayload {
|
||||
/** Exit code of the process. `null` if the process was terminated by a signal on Unix. */
|
||||
code: number | null;
|
||||
/** If the process was terminated by a signal, represents that signal. */
|
||||
signal: number | null;
|
||||
}
|
||||
/** Event payload type */
|
||||
type IOPayload = string | Uint8Array;
|
||||
/**
|
||||
* Opens a path or URL with the system's default app,
|
||||
* or the one specified with `openWith`.
|
||||
*
|
||||
* The `openWith` value must be one of `firefox`, `google chrome`, `chromium` `safari`,
|
||||
* `open`, `start`, `xdg-open`, `gio`, `gnome-open`, `kde-open` or `wslview`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { open } from '@tauri-apps/plugin-shell';
|
||||
* // opens the given URL on the default browser:
|
||||
* await open('https://github.com/tauri-apps/tauri');
|
||||
* // opens the given URL using `firefox`:
|
||||
* await open('https://github.com/tauri-apps/tauri', 'firefox');
|
||||
* // opens a file using the default program:
|
||||
* await open('/path/to/file');
|
||||
* ```
|
||||
*
|
||||
* @param path The path or URL to open.
|
||||
* This value is matched against the string regex defined on `tauri.conf.json > plugins > shell > open`,
|
||||
* which defaults to `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`.
|
||||
* @param openWith The app to open the file or URL with.
|
||||
* Defaults to the system default application for the specified path type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
declare function open(path: string, openWith?: string): Promise<void>;
|
||||
export { Command, Child, EventEmitter, open };
|
||||
export type { IOPayload, CommandEvents, TerminatedPayload, OutputEvents, ChildProcess, SpawnOptions };
|
||||
+446
@@ -0,0 +1,446 @@
|
||||
import { invoke, Channel } from '@tauri-apps/api/core';
|
||||
|
||||
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// SPDX-License-Identifier: MIT
|
||||
/**
|
||||
* Access the system shell.
|
||||
* Allows you to spawn child processes and manage files and URLs using their default application.
|
||||
*
|
||||
* ## Security
|
||||
*
|
||||
* This API has a scope configuration that forces you to restrict the programs and arguments that can be used.
|
||||
*
|
||||
* ### Restricting access to the {@link open | `open`} API
|
||||
*
|
||||
* On the configuration object, `open: true` means that the {@link open} API can be used with any URL,
|
||||
* as the argument is validated with the `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+` regex.
|
||||
* You can change that regex by changing the boolean value to a string, e.g. `open: ^https://github.com/`.
|
||||
*
|
||||
* ### Restricting access to the {@link Command | `Command`} APIs
|
||||
*
|
||||
* The plugin permissions object has a `scope` field that defines an array of CLIs that can be used.
|
||||
* Each CLI is a configuration object `{ name: string, cmd: string, sidecar?: bool, args?: boolean | Arg[] }`.
|
||||
*
|
||||
* - `name`: the unique identifier of the command, passed to the {@link Command.create | Command.create function}.
|
||||
* If it's a sidecar, this must be the value defined on `tauri.conf.json > bundle > externalBin`.
|
||||
* - `cmd`: the program that is executed on this configuration. If it's a sidecar, this value is ignored.
|
||||
* - `sidecar`: whether the object configures a sidecar or a system program.
|
||||
* - `args`: the arguments that can be passed to the program. By default no arguments are allowed.
|
||||
* - `true` means that any argument list is allowed.
|
||||
* - `false` means that no arguments are allowed.
|
||||
* - otherwise an array can be configured. Each item is either a string representing the fixed argument value
|
||||
* or a `{ validator: string }` that defines a regex validating the argument value.
|
||||
*
|
||||
* #### Example scope configuration
|
||||
*
|
||||
* CLI: `git commit -m "the commit message"`
|
||||
*
|
||||
* Capability:
|
||||
* ```json
|
||||
* {
|
||||
* "permissions": [
|
||||
* {
|
||||
* "identifier": "shell:allow-execute",
|
||||
* "allow": [
|
||||
* {
|
||||
* "name": "run-git-commit",
|
||||
* "cmd": "git",
|
||||
* "args": ["commit", "-m", { "validator": "\\S+" }]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ]
|
||||
* }
|
||||
* ```
|
||||
* Usage:
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell'
|
||||
* Command.create('run-git-commit', ['commit', '-m', 'the commit message'])
|
||||
* ```
|
||||
*
|
||||
* Trying to execute any API with a program not configured on the scope results in a promise rejection due to denied access.
|
||||
*
|
||||
* @module
|
||||
*/
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
class EventEmitter {
|
||||
constructor() {
|
||||
/** @ignore */
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-explicit-any
|
||||
this.eventListeners = Object.create(null);
|
||||
}
|
||||
/**
|
||||
* Alias for `emitter.on(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
addListener(eventName, listener) {
|
||||
return this.on(eventName, listener);
|
||||
}
|
||||
/**
|
||||
* Alias for `emitter.off(eventName, listener)`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeListener(eventName, listener) {
|
||||
return this.off(eventName, listener);
|
||||
}
|
||||
/**
|
||||
* Adds the `listener` function to the end of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
on(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName].push(listener);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName`. The
|
||||
* next time `eventName` is triggered, this listener is removed and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
once(eventName, listener) {
|
||||
const wrapper = (arg) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
listener(arg);
|
||||
};
|
||||
return this.addListener(eventName, wrapper);
|
||||
}
|
||||
/**
|
||||
* Removes the all specified listener from the listener array for the event eventName
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
off(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = this.eventListeners[eventName].filter((l) => l !== listener);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Removes all listeners, or those of the specified eventName.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
removeAllListeners(event) {
|
||||
if (event) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
delete this.eventListeners[event];
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
this.eventListeners = Object.create(null);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* @ignore
|
||||
* Synchronously calls each of the listeners registered for the event named`eventName`, in the order they were registered, passing the supplied arguments
|
||||
* to each.
|
||||
*
|
||||
* @returns `true` if the event had listeners, `false` otherwise.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
emit(eventName, arg) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
const listeners = this.eventListeners[eventName];
|
||||
for (const listener of listeners)
|
||||
listener(arg);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Returns the number of listeners listening to the event named `eventName`.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
listenerCount(eventName) {
|
||||
if (eventName in this.eventListeners)
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
return this.eventListeners[eventName].length;
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* Adds the `listener` function to the _beginning_ of the listeners array for the
|
||||
* event named `eventName`. No checks are made to see if the `listener` has
|
||||
* already been added. Multiple calls passing the same combination of `eventName`and `listener` will result in the `listener` being added, and called, multiple
|
||||
* times.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependListener(eventName, listener) {
|
||||
if (eventName in this.eventListeners) {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName].unshift(listener);
|
||||
}
|
||||
else {
|
||||
// eslint-disable-next-line security/detect-object-injection
|
||||
this.eventListeners[eventName] = [listener];
|
||||
}
|
||||
return this;
|
||||
}
|
||||
/**
|
||||
* Adds a **one-time**`listener` function for the event named `eventName` to the_beginning_ of the listeners array. The next time `eventName` is triggered, this
|
||||
* listener is removed, and then invoked.
|
||||
*
|
||||
* Returns a reference to the `EventEmitter`, so that calls can be chained.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
prependOnceListener(eventName, listener) {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
const wrapper = (arg) => {
|
||||
this.removeListener(eventName, wrapper);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
listener(arg);
|
||||
};
|
||||
return this.prependListener(eventName, wrapper);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @since 2.0.0
|
||||
*/
|
||||
class Child {
|
||||
constructor(pid) {
|
||||
this.pid = pid;
|
||||
}
|
||||
/**
|
||||
* Writes `data` to the `stdin`.
|
||||
*
|
||||
* @param data The message to write, either a string or a byte array.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* const child = await command.spawn();
|
||||
* await child.write('message');
|
||||
* await child.write([0, 1, 2, 3, 4, 5]);
|
||||
* ```
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async write(data) {
|
||||
await invoke('plugin:shell|stdin_write', {
|
||||
pid: this.pid,
|
||||
buffer: data
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Kills the child process.
|
||||
*
|
||||
* @returns A promise indicating the success or failure of the operation.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async kill() {
|
||||
await invoke('plugin:shell|kill', {
|
||||
cmd: 'killChild',
|
||||
pid: this.pid
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* The entry point for spawning child processes.
|
||||
* It emits the `close` and `error` events.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('node');
|
||||
* command.on('close', data => {
|
||||
* console.log(`command finished with code ${data.code} and signal ${data.signal}`)
|
||||
* });
|
||||
* command.on('error', error => console.error(`command error: "${error}"`));
|
||||
* command.stdout.on('data', line => console.log(`command stdout: "${line}"`));
|
||||
* command.stderr.on('data', line => console.log(`command stderr: "${line}"`));
|
||||
*
|
||||
* const child = await command.spawn();
|
||||
* console.log('pid:', child.pid);
|
||||
* ```
|
||||
*
|
||||
* @since 2.0.0
|
||||
*
|
||||
*/
|
||||
class Command extends EventEmitter {
|
||||
/**
|
||||
* @ignore
|
||||
* Creates a new `Command` instance.
|
||||
*
|
||||
* @param program The program name to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
* @param args Program arguments.
|
||||
* @param options Spawn options.
|
||||
*/
|
||||
constructor(program, args = [], options) {
|
||||
super();
|
||||
/** Event emitter for the `stdout`. Emits the `data` event. */
|
||||
this.stdout = new EventEmitter();
|
||||
/** Event emitter for the `stderr`. Emits the `data` event. */
|
||||
this.stderr = new EventEmitter();
|
||||
this.program = program;
|
||||
this.args = typeof args === 'string' ? [args] : args;
|
||||
this.options = options ?? {};
|
||||
}
|
||||
/**
|
||||
* Creates a command to execute the given program.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.create('my-app', ['run', 'tauri']);
|
||||
* const output = await command.execute();
|
||||
* ```
|
||||
*
|
||||
* @param program The program to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
*/
|
||||
static create(program, args = [], options) {
|
||||
return new Command(program, args, options);
|
||||
}
|
||||
/**
|
||||
* Creates a command to execute the given sidecar program.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const command = Command.sidecar('my-sidecar');
|
||||
* const output = await command.execute();
|
||||
* ```
|
||||
*
|
||||
* @param program The program to execute.
|
||||
* It must be configured in your project's capabilities.
|
||||
*/
|
||||
static sidecar(program, args = [], options) {
|
||||
const instance = new Command(program, args, options);
|
||||
instance.options.sidecar = true;
|
||||
return instance;
|
||||
}
|
||||
/**
|
||||
* Executes the command as a child process, returning a handle to it.
|
||||
*
|
||||
* @returns A promise resolving to the child process handle.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async spawn() {
|
||||
const program = this.program;
|
||||
const args = this.args;
|
||||
const options = this.options;
|
||||
if (typeof args === 'object') {
|
||||
Object.freeze(args);
|
||||
}
|
||||
const onEvent = new Channel();
|
||||
onEvent.onmessage = (event) => {
|
||||
switch (event.event) {
|
||||
case 'Error':
|
||||
this.emit('error', event.payload);
|
||||
break;
|
||||
case 'Terminated':
|
||||
this.emit('close', event.payload);
|
||||
break;
|
||||
case 'Stdout':
|
||||
this.stdout.emit('data', event.payload);
|
||||
break;
|
||||
case 'Stderr':
|
||||
this.stderr.emit('data', event.payload);
|
||||
break;
|
||||
}
|
||||
};
|
||||
return await invoke('plugin:shell|spawn', {
|
||||
program,
|
||||
args,
|
||||
options,
|
||||
onEvent
|
||||
}).then((pid) => new Child(pid));
|
||||
}
|
||||
/**
|
||||
* Executes the command as a child process, waiting for it to finish and collecting all of its output.
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { Command } from '@tauri-apps/plugin-shell';
|
||||
* const output = await Command.create('echo', 'message').execute();
|
||||
* assert(output.code === 0);
|
||||
* assert(output.signal === null);
|
||||
* assert(output.stdout === 'message');
|
||||
* assert(output.stderr === '');
|
||||
* ```
|
||||
*
|
||||
* @returns A promise resolving to the child process output.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async execute() {
|
||||
const program = this.program;
|
||||
const args = this.args;
|
||||
const options = this.options;
|
||||
if (typeof args === 'object') {
|
||||
Object.freeze(args);
|
||||
}
|
||||
return await invoke('plugin:shell|execute', {
|
||||
program,
|
||||
args,
|
||||
options
|
||||
});
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Opens a path or URL with the system's default app,
|
||||
* or the one specified with `openWith`.
|
||||
*
|
||||
* The `openWith` value must be one of `firefox`, `google chrome`, `chromium` `safari`,
|
||||
* `open`, `start`, `xdg-open`, `gio`, `gnome-open`, `kde-open` or `wslview`.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { open } from '@tauri-apps/plugin-shell';
|
||||
* // opens the given URL on the default browser:
|
||||
* await open('https://github.com/tauri-apps/tauri');
|
||||
* // opens the given URL using `firefox`:
|
||||
* await open('https://github.com/tauri-apps/tauri', 'firefox');
|
||||
* // opens a file using the default program:
|
||||
* await open('/path/to/file');
|
||||
* ```
|
||||
*
|
||||
* @param path The path or URL to open.
|
||||
* This value is matched against the string regex defined on `tauri.conf.json > plugins > shell > open`,
|
||||
* which defaults to `^((mailto:\w+)|(tel:\w+)|(https?://\w+)).+`.
|
||||
* @param openWith The app to open the file or URL with.
|
||||
* Defaults to the system default application for the specified path type.
|
||||
*
|
||||
* @since 2.0.0
|
||||
*/
|
||||
async function open(path, openWith) {
|
||||
await invoke('plugin:shell|open', {
|
||||
path,
|
||||
with: openWith
|
||||
});
|
||||
}
|
||||
|
||||
export { Child, Command, EventEmitter, open };
|
||||
+1
@@ -0,0 +1 @@
|
||||
export {};
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
{
|
||||
"name": "@tauri-apps/plugin-shell",
|
||||
"version": "2.3.5",
|
||||
"license": "MIT OR Apache-2.0",
|
||||
"authors": [
|
||||
"Tauri Programme within The Commons Conservancy"
|
||||
],
|
||||
"repository": "https://github.com/tauri-apps/plugins-workspace",
|
||||
"type": "module",
|
||||
"types": "./dist-js/index.d.ts",
|
||||
"main": "./dist-js/index.cjs",
|
||||
"module": "./dist-js/index.js",
|
||||
"exports": {
|
||||
"types": "./dist-js/index.d.ts",
|
||||
"import": "./dist-js/index.js",
|
||||
"require": "./dist-js/index.cjs"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "rollup -c"
|
||||
},
|
||||
"files": [
|
||||
"dist-js",
|
||||
"README.md",
|
||||
"LICENSE"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tauri-apps/api": "^2.10.1"
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user