Skip to content

Latest commit

 

History

History
217 lines (168 loc) · 7.64 KB

npm-usage.md

File metadata and controls

217 lines (168 loc) · 7.64 KB
ms.custom mslearn

Use winapp from TypeScript or JavaScript

npm install @microsoft/winappcli

The package includes the Windows CLI and typed functions for calling it from Node.js. Run your script on Windows. Each command function launches the CLI, waits for it to finish, and captures its output.

Initialize a project

Run this script from your application's directory:

import { init } from '@microsoft/winappcli';

const result = await init({ useDefaults: true });
console.log(result.stdout);

init creates the manifest and assets and sets up SDK packages and projections. After cloning a project that already has winapp.yaml, use restore() instead. See initialization and restore for the CLI workflow.

To work in another existing directory, pass cwd. Paths passed to the command are resolved in that directory, not relative to your script.

Package build output

Build your application first, then package its output folder:

import { certGenerate, packageApp } from '@microsoft/winappcli';

await certGenerate({ output: './devcert.pfx' });
const result = await packageApp({
  inputFolder: './dist',
  cert: './devcert.pfx',
  output: './MyApp.msix',
});
console.log(result.stdout);

The manifest must describe your executable and match the signing certificate's publisher. The generated certificate is for local development only; it uses the publicly known default password password. See packaging, code signing, and the Electron guides for preparing your application's package layout and trusting a development certificate.

Find command functions and options

Use your editor's completion and the package's .d.ts declarations for the full API of the version you installed. Command paths generally become camel-case functions, and hyphenated options become camel-case properties:

CLI JavaScript/TypeScript
winapp init --use-defaults init({ useDefaults: true })
winapp restore restore()
winapp cert generate --output devcert.pfx certGenerate({ output: 'devcert.pfx' })
winapp pack ./dist packageApp({ inputFolder: './dist' })
winapp run MyApp.csproj run({ input: 'MyApp.csproj' })
winapp ui inspect --app notepad uiInspect({ app: 'notepad' })

packageApp is the function for packaging; it is not named pack or package. See CLI usage for each command's behavior, prerequisites, and examples. Use npx winapp <command> --help for exact flags or npx winapp --cli-schema for the installed CLI's complete machine-readable command tree.

Every command's options object also accepts these shared properties:

Property Use
cwd Run in a specified existing directory. Defaults to the current working directory.
quiet Suppress progress messages.
verbose Include diagnostic output.
signal Cancel the native process with an AbortSignal.
workflowId Group related UI calls into one desktop workflow.

Read results and handle failures

Command functions return a promise containing exitCode, stdout, and stderr. Successful calls have exitCode: 0. A nonzero CLI exit rejects the promise with an Error carrying those same three properties; launch failures reject with an error message, and cancellation rejects with an AbortError.

import { packageApp } from '@microsoft/winappcli';

try {
  const result = await packageApp({ inputFolder: './dist', noSign: true });
  console.log(result.stdout);
} catch (error) {
  if (error instanceof Error) {
    console.error(error.message);
  }
  throw error;
}

If a call fails, inspect its error message and captured output, correct the reported path, manifest, signing, or prerequisite problem, and retry. The wrapper captures text; it does not automatically parse JSON output. For commands that support json, request it and parse stdout:

import { uiInspect } from '@microsoft/winappcli';

const result = await uiInspect({ app: 'notepad', json: true });
const tree: unknown = JSON.parse(result.stdout);
console.log(tree);

Open the target application before inspecting it.

perfAnalyze with json: true is the one exception to rejecting on a nonzero exit. When the capture is missing some evidence, it resolves with exitCode: 1 and the usable results in stdout. Check coverage.complete before treating the results as complete:

import { perfAnalyze } from '@microsoft/winappcli';

const result = await perfAnalyze({ directory: './capture', json: true });
const evidence = JSON.parse(result.stdout);
if (!evidence.coverage.complete) {
  console.warn(result.stderr);
}

Calls are non-interactive

Command wrappers capture output and use piped stdin, so commands cannot ask for interactive input. Supply the options and credentials your command needs. init and newCommand support defaults; other commands may fail if a required selection is missing. For Azure signing, supply metadataFile or all of subscription, resourceGroup, account, and profile, and authenticate non-interactively beforehand. See Azure signing.

Cancel a call

import { uiInspect } from '@microsoft/winappcli';

const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 30_000);
try {
  await uiInspect({ app: 'notepad', signal: controller.signal });
} catch (error) {
  if (error instanceof Error && error.name === 'AbortError') {
    console.error('The inspection was cancelled.');
  }
  throw error;
} finally {
  clearTimeout(timeout);
}

Cancellation stops the whole native invocation, including a wait for the desktop. On Windows it force-terminates the process, so cleanup may not run and completed UI actions are not undone. Cancelling a recording can leave an incomplete video.

Coordinate UI calls and record a bounded video

Desktop-sensitive commands coordinate automatically, even without workflowId. Pass the same ID to related calls when they should retain the desktop between commands. Give each independent workflow its own ID.

import { randomUUID } from 'node:crypto';
import { uiInspect, uiYield } from '@microsoft/winappcli';

const workflowId = randomUUID();
try {
  const result = await uiInspect({ app: 'notepad', workflowId });
  console.log(result.stdout);
  // Use selectors from this inspection for subsequent UI calls with the same ID.
} finally {
  await uiYield({ workflowId });
}

workflowId is passed only to the child process; it does not change process.env. See coordinating concurrent UI workflows for how desktop turns are shared.

uiRecord and targetRecord require a finite, positive durationSec:

import { uiRecord } from '@microsoft/winappcli';

await uiRecord({
  app: 'notepad',
  durationSec: 5,
  output: './notepad.mp4',
});

Use the same workflowId for recording and concurrent UI actions when they belong to one workflow. Do not use cancellation as normal recording completion. See UI recording for capture options.

Electron and Node-only tools

The package also exports addElectronDebugIdentity, clearElectronDebugIdentity, addMsixIdentityToExe, and execWithBuildTools. These utilities have their own result types; use the installed declarations and Electron guides for their options and prerequisites.

Some npm CLI operations are not command-function exports. Use the node commands for native addon scaffolding and JavaScript binding generation.