|
@@ -1,675 +0,0 @@
|
|
|
-// 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.
|
|
|
- *
|
|
|
- * This package is also accessible with `window.__TAURI__.shell` when [`build.withGlobalTauri`](https://tauri.app/v1/api/config/#buildconfig.withglobaltauri) in `tauri.conf.json` is set to `true`.
|
|
|
- *
|
|
|
- * The APIs must be added to [`tauri.allowlist.shell`](https://tauri.app/v1/api/config/#allowlistconfig.shell) in `tauri.conf.json`:
|
|
|
- * ```json
|
|
|
- * {
|
|
|
- * "tauri": {
|
|
|
- * "allowlist": {
|
|
|
- * "shell": {
|
|
|
- * "all": true, // enable all shell APIs
|
|
|
- * "execute": true, // enable process spawn APIs
|
|
|
- * "sidecar": true, // enable spawning sidecars
|
|
|
- * "open": true // enable opening files/URLs using the default program
|
|
|
- * }
|
|
|
- * }
|
|
|
- * }
|
|
|
- * }
|
|
|
- * ```
|
|
|
- * It is recommended to allowlist only the APIs you use for optimal bundle size and security.
|
|
|
- *
|
|
|
- * ## 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 allowlist, `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 `shell` allowlist 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 > tauri > 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"`
|
|
|
- *
|
|
|
- * Configuration:
|
|
|
- * ```json
|
|
|
- * {
|
|
|
- * "scope": [
|
|
|
- * {
|
|
|
- * "name": "run-git-commit",
|
|
|
- * "cmd": "git",
|
|
|
- * "args": ["commit", "-m", { "validator": "\\S+" }]
|
|
|
- * }
|
|
|
- * ]
|
|
|
- * }
|
|
|
- * ```
|
|
|
- * Usage:
|
|
|
- * ```typescript
|
|
|
- * import { Command } from '@tauri-apps/api/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
|
|
|
- */
|
|
|
-
|
|
|
-import { invokeTauriCommand } from './helpers/tauri'
|
|
|
-import { transformCallback } from './tauri'
|
|
|
-
|
|
|
-/**
|
|
|
- * @since 1.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 1.1.0
|
|
|
- * */
|
|
|
- encoding?: string
|
|
|
-}
|
|
|
-
|
|
|
-/** @ignore */
|
|
|
-interface InternalSpawnOptions extends SpawnOptions {
|
|
|
- sidecar?: boolean
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @since 1.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
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Spawns a process.
|
|
|
- *
|
|
|
- * @ignore
|
|
|
- * @param program The name of the scoped command.
|
|
|
- * @param onEvent Event handler.
|
|
|
- * @param args Program arguments.
|
|
|
- * @param options Configuration for the process spawn.
|
|
|
- * @returns A promise resolving to the process id.
|
|
|
- */
|
|
|
-async function execute<O extends IOPayload>(
|
|
|
- onEvent: (event: CommandEvent<O>) => void,
|
|
|
- program: string,
|
|
|
- args: string | string[] = [],
|
|
|
- options?: InternalSpawnOptions
|
|
|
-): Promise<number> {
|
|
|
- if (typeof args === 'object') {
|
|
|
- Object.freeze(args)
|
|
|
- }
|
|
|
-
|
|
|
- return invokeTauriCommand<number>({
|
|
|
- __tauriModule: 'Shell',
|
|
|
- message: {
|
|
|
- cmd: 'execute',
|
|
|
- program,
|
|
|
- args,
|
|
|
- options,
|
|
|
- onEventFn: transformCallback(onEvent)
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @since 1.0.0
|
|
|
- */
|
|
|
-class EventEmitter<E extends Record<string, any>> {
|
|
|
- /** @ignore */
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
|
- private eventListeners: Record<keyof E, Array<(arg: any) => void>> =
|
|
|
- Object.create(null)
|
|
|
-
|
|
|
- /**
|
|
|
- * Alias for `emitter.on(eventName, listener)`.
|
|
|
- *
|
|
|
- * @since 1.1.0
|
|
|
- */
|
|
|
- addListener<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- return this.on(eventName, listener)
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Alias for `emitter.off(eventName, listener)`.
|
|
|
- *
|
|
|
- * @since 1.1.0
|
|
|
- */
|
|
|
- removeListener<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- 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 1.0.0
|
|
|
- */
|
|
|
- on<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- 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 1.1.0
|
|
|
- */
|
|
|
- once<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- const wrapper = (arg: E[typeof eventName]): void => {
|
|
|
- this.removeListener(eventName, wrapper)
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
|
- 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 1.1.0
|
|
|
- */
|
|
|
- off<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- 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 1.1.0
|
|
|
- */
|
|
|
- removeAllListeners<N extends keyof E>(event?: N): this {
|
|
|
- if (event) {
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-dynamic-delete,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.
|
|
|
- */
|
|
|
- emit<N extends keyof E>(eventName: N, arg: E[typeof eventName]): boolean {
|
|
|
- if (eventName in this.eventListeners) {
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment,security/detect-object-injection
|
|
|
- const listeners = this.eventListeners[eventName]
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
|
- for (const listener of listeners) listener(arg)
|
|
|
- return true
|
|
|
- }
|
|
|
- return false
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Returns the number of listeners listening to the event named `eventName`.
|
|
|
- *
|
|
|
- * @since 1.1.0
|
|
|
- */
|
|
|
- listenerCount<N extends keyof E>(eventName: N): number {
|
|
|
- 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 1.1.0
|
|
|
- */
|
|
|
- prependListener<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- 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 1.1.0
|
|
|
- */
|
|
|
- prependOnceListener<N extends keyof E>(
|
|
|
- eventName: N,
|
|
|
- listener: (arg: E[typeof eventName]) => void
|
|
|
- ): this {
|
|
|
- const wrapper = (arg: any): void => {
|
|
|
- this.removeListener(eventName, wrapper)
|
|
|
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
|
|
- listener(arg)
|
|
|
- }
|
|
|
- return this.prependListener(eventName, wrapper)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * @since 1.1.0
|
|
|
- */
|
|
|
-class Child {
|
|
|
- /** The child process `pid`. */
|
|
|
- pid: number
|
|
|
-
|
|
|
- constructor(pid: number) {
|
|
|
- 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/api/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.
|
|
|
- */
|
|
|
- async write(data: IOPayload): Promise<void> {
|
|
|
- return invokeTauriCommand({
|
|
|
- __tauriModule: 'Shell',
|
|
|
- message: {
|
|
|
- cmd: 'stdinWrite',
|
|
|
- pid: this.pid,
|
|
|
- // correctly serialize Uint8Arrays
|
|
|
- buffer: typeof data === 'string' ? data : Array.from(data)
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * Kills the child process.
|
|
|
- *
|
|
|
- * @returns A promise indicating the success or failure of the operation.
|
|
|
- */
|
|
|
- async kill(): Promise<void> {
|
|
|
- return invokeTauriCommand({
|
|
|
- __tauriModule: 'Shell',
|
|
|
- message: {
|
|
|
- cmd: 'killChild',
|
|
|
- pid: this.pid
|
|
|
- }
|
|
|
- })
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-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/api/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 1.1.0
|
|
|
- *
|
|
|
- */
|
|
|
-class Command<O extends IOPayload> extends EventEmitter<CommandEvents> {
|
|
|
- /** @ignore Program to execute. */
|
|
|
- private readonly program: string
|
|
|
- /** @ignore Program arguments */
|
|
|
- private readonly args: string[]
|
|
|
- /** @ignore Spawn options. */
|
|
|
- private readonly options: InternalSpawnOptions
|
|
|
- /** Event emitter for the `stdout`. Emits the `data` event. */
|
|
|
- readonly stdout = new EventEmitter<OutputEvents<O>>()
|
|
|
- /** Event emitter for the `stderr`. Emits the `data` event. */
|
|
|
- readonly stderr = new EventEmitter<OutputEvents<O>>()
|
|
|
-
|
|
|
- /**
|
|
|
- * @ignore
|
|
|
- * Creates a new `Command` instance.
|
|
|
- *
|
|
|
- * @param program The program name to execute.
|
|
|
- * It must be configured on `tauri.conf.json > tauri > allowlist > shell > scope`.
|
|
|
- * @param args Program arguments.
|
|
|
- * @param options Spawn options.
|
|
|
- */
|
|
|
- private constructor(
|
|
|
- program: string,
|
|
|
- args: string | string[] = [],
|
|
|
- options?: SpawnOptions
|
|
|
- ) {
|
|
|
- super()
|
|
|
- this.program = program
|
|
|
- this.args = typeof args === 'string' ? [args] : args
|
|
|
- this.options = options ?? {}
|
|
|
- }
|
|
|
-
|
|
|
- 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>
|
|
|
-
|
|
|
- /**
|
|
|
- * Creates a command to execute the given program.
|
|
|
- * @example
|
|
|
- * ```typescript
|
|
|
- * import { Command } from '@tauri-apps/api/shell';
|
|
|
- * const command = Command.create('my-app', ['run', 'tauri']);
|
|
|
- * const output = await command.execute();
|
|
|
- * ```
|
|
|
- *
|
|
|
- * @param program The program to execute.
|
|
|
- * It must be configured on `tauri.conf.json > tauri > allowlist > shell > scope`.
|
|
|
- */
|
|
|
- static create<O extends IOPayload>(
|
|
|
- program: string,
|
|
|
- args: string | string[] = [],
|
|
|
- options?: SpawnOptions
|
|
|
- ): Command<O> {
|
|
|
- return new Command(program, args, options)
|
|
|
- }
|
|
|
-
|
|
|
- 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>
|
|
|
-
|
|
|
- /**
|
|
|
- * Creates a command to execute the given sidecar program.
|
|
|
- * @example
|
|
|
- * ```typescript
|
|
|
- * import { Command } from '@tauri-apps/api/shell';
|
|
|
- * const command = Command.sidecar('my-sidecar');
|
|
|
- * const output = await command.execute();
|
|
|
- * ```
|
|
|
- *
|
|
|
- * @param program The program to execute.
|
|
|
- * It must be configured on `tauri.conf.json > tauri > allowlist > shell > scope`.
|
|
|
- */
|
|
|
- static sidecar<O extends IOPayload>(
|
|
|
- program: string,
|
|
|
- args: string | string[] = [],
|
|
|
- options?: SpawnOptions
|
|
|
- ): Command<O> {
|
|
|
- const instance = new Command<O>(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.
|
|
|
- */
|
|
|
- async spawn(): Promise<Child> {
|
|
|
- return execute<O>(
|
|
|
- (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
|
|
|
- }
|
|
|
- },
|
|
|
- this.program,
|
|
|
- this.args,
|
|
|
- this.options
|
|
|
- ).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/api/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.
|
|
|
- */
|
|
|
- async execute(): Promise<ChildProcess<O>> {
|
|
|
- return new Promise((resolve, reject) => {
|
|
|
- this.on('error', reject)
|
|
|
-
|
|
|
- const stdout: O[] = []
|
|
|
- const stderr: O[] = []
|
|
|
- this.stdout.on('data', (line: O) => {
|
|
|
- stdout.push(line)
|
|
|
- })
|
|
|
- this.stderr.on('data', (line: O) => {
|
|
|
- stderr.push(line)
|
|
|
- })
|
|
|
-
|
|
|
- this.on('close', (payload: TerminatedPayload) => {
|
|
|
- resolve({
|
|
|
- code: payload.code,
|
|
|
- signal: payload.signal,
|
|
|
- stdout: this.collectOutput(stdout) as O,
|
|
|
- stderr: this.collectOutput(stderr) as O
|
|
|
- })
|
|
|
- })
|
|
|
-
|
|
|
- this.spawn().catch(reject)
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- /** @ignore */
|
|
|
- private collectOutput(events: O[]): string | Uint8Array {
|
|
|
- if (this.options.encoding === 'raw') {
|
|
|
- return events.reduce<Uint8Array>((p, c) => {
|
|
|
- return new Uint8Array([...p, ...(c as Uint8Array), 10])
|
|
|
- }, new Uint8Array())
|
|
|
- } else {
|
|
|
- return events.join('\n')
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * Describes the event message received from the command.
|
|
|
- */
|
|
|
-interface Event<T, V> {
|
|
|
- event: T
|
|
|
- payload: V
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * 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
|
|
|
-
|
|
|
-/** Events emitted by the child process. */
|
|
|
-type CommandEvent<O extends IOPayload> =
|
|
|
- | Event<'Stdout', O>
|
|
|
- | Event<'Stderr', O>
|
|
|
- | Event<'Terminated', TerminatedPayload>
|
|
|
- | Event<'Error', string>
|
|
|
-
|
|
|
-/**
|
|
|
- * 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/api/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 > tauri > allowlist > 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 1.0.0
|
|
|
- */
|
|
|
-async function open(path: string, openWith?: string): Promise<void> {
|
|
|
- return invokeTauriCommand({
|
|
|
- __tauriModule: 'Shell',
|
|
|
- message: {
|
|
|
- cmd: 'open',
|
|
|
- path,
|
|
|
- with: openWith
|
|
|
- }
|
|
|
- })
|
|
|
-}
|
|
|
-
|
|
|
-export { Command, Child, EventEmitter, open }
|
|
|
-export type {
|
|
|
- IOPayload,
|
|
|
- CommandEvents,
|
|
|
- TerminatedPayload,
|
|
|
- OutputEvents,
|
|
|
- ChildProcess,
|
|
|
- SpawnOptions
|
|
|
-}
|