From a186570dc80c0496cd763756983ac8cce1fa1c52 Mon Sep 17 00:00:00 2001 From: hensm Date: Fri, 19 Aug 2022 03:09:59 +0100 Subject: [PATCH] Replace minimist, convert build scripts to ES modules + misc refactoring --- README.md | 146 +++++++++-------- app/bin/build.js | 241 ++++++++++++++++----------- app/bin/install-manifest.js | 88 +++++----- app/bin/lib/paths.js | 95 ++++++----- app/config.json | 9 + app/package-lock.json | 292 ++++++++++++++++++++++----------- app/package.json | 13 +- app/src/bridge/index.ts | 4 +- app/src/daemon.ts | 12 +- app/src/main.ts | 97 +++++------ app/tsconfig.json | 11 +- ext/bin/build.js | 57 ++++--- ext/bin/lib/copyFilesPlugin.js | 17 +- ext/package-lock.json | 104 ++++++++---- ext/package.json | 4 +- package-lock.json | 13 -- package.json | 4 - 17 files changed, 702 insertions(+), 505 deletions(-) create mode 100644 app/config.json diff --git a/README.md b/README.md index c2515da..644f3b8 100644 --- a/README.md +++ b/README.md @@ -19,10 +19,9 @@ The bridge application is currently supported on Windows, macOS and Linux. **Note**: These packages are maintained by third parties and support likely will not be provided for any issues specific to these packages. -- **Arch Linux (AUR)** - - `fx_cast` — https://aur.archlinux.org/packages/fx_cast - - `fx_cast-bin` — https://aur.archlinux.org/packages/fx_cast-bin - +- **Arch Linux (AUR)** + - `fx_cast` — https://aur.archlinux.org/packages/fx_cast + - `fx_cast-bin` — https://aur.archlinux.org/packages/fx_cast-bin ### Daemon Configuration @@ -30,10 +29,13 @@ The bridge application is currently supported on Windows, macOS and Linux. Daemon configuration (systemd) 1. Create a new `fx_cast` user: + ```sh $ sudo useradd --system fx_cast ``` + 2. Create a service file in `/etc/systemd/system/fx_cast.service`: + ``` [Unit] Description=fx_cast daemon @@ -46,12 +48,14 @@ Restart=always [Install] WantedBy=multi-user.target ``` + 3. Enable the service: + ```sh $ sudo systemctl enable --now fx_cast ``` - + ## Usage @@ -68,36 +72,43 @@ Whitelisted sites should then display a cast button as in Chrome, provided they' ## Building ### Requirements -* Node.js v16.x.x -* Native build tools (see [here](https://github.com/nodejs/node-gyp#installation)) -* Bonjour/Avahi (on Windows/Linux respectively) + +- Node.js v16.x.x +- Native build tools (see [here](https://github.com/nodejs/node-gyp#installation)) +- Bonjour/Avahi (on Windows/Linux respectively) ### Installing dependencies #### Windows: -* [Bonjour SDK for Windows](https://developer.apple.com/download/more/?=Bonjour%20SDK%20for%20Windows) -* [NSIS](https://nsis.sourceforge.io/Download) + +- [Bonjour SDK for Windows](https://developer.apple.com/download/more/?=Bonjour%20SDK%20for%20Windows) +- [NSIS](https://nsis.sourceforge.io/Download) #### Debian / Ubuntu: -````sh + +```sh $ sudo apt install libavahi-compat-libdnssd-dev dpkg rpm -```` +``` + Runtime packages: `avahi-daemon`. #### Fedora: -````sh + +```sh $ sudo dnf install avahi-compat-libdns_sd-devel dpkg rpm-build -```` +``` + Runtime packages: `avahi`, `nss-mdns`. #### Arch Linux: -````sh + +```sh $ sudo pacman -S avahi dpkg rpm-tools -```` +``` ### Instructions -````sh +```sh $ git clone https://github.com/hensm/fx_cast.git $ cd fx_cast $ npm install @@ -108,61 +119,68 @@ $ npm run build # install. Call `remove-manifest` to restore previous state. $ npm run install-manifest $ npm run remove-manifest -```` +``` This will build the ext and app, outputting to `dist/`: -- `dist/app/` - ... contains the built bridge with launcher script and manifest (with the path pointing that script). The `install-manifest` npm script copies this manifest to the proper location (or adds its current location to the registry on Windows). -- `dist/ext/` - ... contains the unpacked extension. +- `dist/app/` + ... contains the built bridge with launcher script and manifest (with the path pointing that script). The `install-manifest` npm script copies this manifest to the proper location (or adds its current location to the registry on Windows). +- `dist/ext/` + ... contains the unpacked extension. Watching ext changes: -````sh +```sh $ npm run watch:ext -```` +``` Launch Firefox with built extension (run in separate terminal): -````sh +```sh $ npm run start:ext -```` +``` #### 32-bit on Windows Building a 32-bit version is only supported for Windows. If you're building from a 64-bit system, you'll also need to rebuild any native dependencies as 32-bit. -````sh +```sh $ npm clean-install --prefix ./app --arch=ia32 # If on a 64-bit system # If building without packaging -$ npm run build:app -- -- --arch=x86 --usePkg +$ npm run build:app -- -- --arch=x86 --use-pkg # If packaging $ npm run package:app -- -- --arch=x86 -```` +``` ### Build scripts Extension build script (`build:ext`) arguments: -- `--package` - Should package with web-ext. -- `--watch` - Should run webpack in watch mode. -- `--mirroringAppId` `""` - Provide an alternative default mirroring receiver app ID. -- `--mode` `"production"`, `"development"` - Run webpack in a different mode. Defaults to `"development"` unless combined with `--package`. +- `--watch` + Rebuild on changes. Incompatible with `--package`. +- `--package` + Package with web-ext. +- `--mode` `"development"`, `"production"` + Sets build mode. Defaults to `development` unless packaging. Bridge build script (`build:app`) arguments: -- `--usePkg` - Creates a single executable instead of a compiled JavaScript files and a launcher script. -- `--package` + +- `--package` Builds and creates installer packages for distribution. -- `--arch` `"x64"`,`"x86"` - Select platform arch to build for. Defaults to current platform arch. +- `--package-type` `"deb"`, `"rpm"` + Linux installer package type. +- `--use-pkg` + Create single binary with pkg. +- `--arch` `"x64"`, `"x86"`, `"arm64"` + Select platform arch to build for. Defaults to current arch. + + | Platform | Supported Architectures | + | --------- | ----------------------- | + | `Windows` | `x86`, `x64` | + | `macOS` | `x64`, `arm64` | + | `Linux` | `x64` | ### Packaging @@ -172,10 +190,10 @@ Build and package extension and bridge application for current platform: $ npm run package ``` -- `dist/app/` - ... contains the installer package: `fx_cast_bridge--.(pkg|deb|rpm|exe)` -- `dist/ext/` - ... contains the built extension archive: `fx_cast-.xpi`. +- `dist/app/` + ... contains the installer package: `fx_cast_bridge--.(pkg|deb|rpm|exe)` +- `dist/ext/` + ... contains the built extension archive: `fx_cast-.xpi`. Packaging examples: @@ -184,16 +202,10 @@ $ npm run package:ext # Packaging extension $ npm run package:app # Packaging bridge application # Linux platforms -$ npm run package:app -- -- --packageType=deb -$ npm run package:app -- -- --packageType=rpm +$ npm run package:app -- -- --package-type=deb +$ npm run package:app -- -- --package-type=rpm ``` -Bridge package script arguments (includes the build script arguments): - -- `--packageType` `"deb"`,`"rpm"` - Select the package type. Defaults to `deb`. Only relevant when building for Linux. - - ### Testing Testing requires geckodriver (or chromedriver for Chrome parity testing). See [selenium-webdriver](https://www.npmjs.com/package/selenium-webdriver#installation) installation instructions (ignore `npm install`). @@ -212,24 +224,25 @@ $ npm test $ SELENIUM_BROWSER=chrome npm test ``` - ## Video Demos -These are somewhat outdated now, but show the basic function of the extension: +These are somewhat outdated now, but show the basic function of the extension: + [fx_cast Netflix](https://www.youtube.com/watch?v=Ex9dWKYguEE) [fx_cast HTML5](https://www.youtube.com/watch?v=16r8lQKeEX8) - ## Credit -- [electron-chromecast](https://github.com/GPMDP/electron-chromecast)[^electron] -- Icons by [icons8](https://icons8.com/): - - `ext/src/ui/options/assets/icons8-cancel-120.png` - - `ext/src/ui/options/assets/icons8-ok-120.png` - - `ext/src/ui/options/assets/icons8-warn-120.png` +- [electron-chromecast](https://github.com/GPMDP/electron-chromecast)[^electron] +- Icons by [icons8](https://icons8.com/): + - `ext/src/ui/options/assets/icons8-cancel-120.png` + - `ext/src/ui/options/assets/icons8-ok-120.png` + - `ext/src/ui/options/assets/icons8-warn-120.png` ## Donations + ### PayPal +

Donate with PayPal button @@ -237,9 +250,6 @@ These are somewhat outdated now, but show the basic function of the extension: Donate with PayPal

-[^arch]: - By default, Arch does not configure Avahi to resolve `.local` hostnames via the name service switch (NSS), and the underlying mdns module used by this project relies on [`getaddrinfo`](https://en.wikipedia.org/wiki/Getaddrinfo) to resolve these hostnames correctly. -[^cast_app]: - Some sites may only function properly when initiating casting from the in-page player buttons. -[^electron]: - Since it seems to be causing confusion, this project does not use electron. The electron-chromecast library was only used as a reference for the initial implementation of the API. +[^arch]: By default, Arch does not configure Avahi to resolve `.local` hostnames via the name service switch (NSS), and the underlying mdns module used by this project relies on [`getaddrinfo`](https://en.wikipedia.org/wiki/Getaddrinfo) to resolve these hostnames correctly. +[^cast_app]: Some sites may only function properly when initiating casting from the in-page player buttons. +[^electron]: Since it seems to be causing confusion, this project does not use electron. The electron-chromecast library was only used as a reference for the initial implementation of the API. diff --git a/app/bin/build.js b/app/bin/build.js index 2a5a09e..ed44379 100644 --- a/app/bin/build.js +++ b/app/bin/build.js @@ -1,34 +1,44 @@ -"use strict"; +// @ts-check -const fs = require("fs-extra"); -const os = require("os"); -const path = require("path"); +import fs from "fs-extra"; +import os from "os"; +import path from "path"; +import url from "url"; +import { spawnSync } from "child_process"; -const minimist = require("minimist"); -const mustache = require("mustache"); -const pkg = require("pkg"); +import mustache from "mustache"; +import pkg from "pkg"; +import yargs from "yargs"; -const { spawnSync } = require("child_process"); +import config from "../config.json" assert { type: "json" }; +import * as paths from "./lib/paths.js"; -const meta = require("../package.json"); -const paths = require("./lib/paths"); - -const { author, homepage } = require("../../package.json"); - -const EXTENSION_ID = "fx_cast@matt.tf"; - -// Command line args -const argv = minimist(process.argv.slice(2), { - boolean: ["usePkg", "package"], - string: ["arch", "packageType", "nodeVersion"], - default: { - arch: os.arch(), - package: false, - // Linux package type (deb/rpm) - packageType: "deb", - nodeVersion: "16" - } -}); +const argv = await yargs() + .help() + .version(false) + .option("package", { + describe: "Create installer package", + type: "boolean" + }) + .option("package-type", { + describe: "Linux package type", + choices: ["deb", "rpm"], + default: "deb" + }) + .option("use-pkg", { + describe: "Create single binary with pkg", + type: "boolean" + }) + .option("arch", { + describe: "Set build architecture", + default: os.arch() + }) + .option("node-version", { + describe: "Node.js version to target", + default: "16" + }) + .conflicts("use-pkg", "package") + .parse(process.argv); const supportedTargets = { win32: ["x86", "x64"], @@ -45,6 +55,8 @@ if (!supportedTargets[process.platform]?.includes(argv.arch)) { process.exit(1); } +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + const ROOT_PATH = path.join(__dirname, ".."); const BUILD_PATH = path.join(ROOT_PATH, "build"); @@ -57,10 +69,10 @@ const spawnOptions = { * Shouldn't exist, but cleanup and re-create any existing * build directories, just in case. */ -fs.removeSync(BUILD_PATH); -fs.removeSync(paths.DIST_PATH, { recursive: true }); -fs.ensureDirSync(BUILD_PATH); -fs.ensureDirSync(paths.DIST_PATH, { recursive: true }); +fs.rmSync(BUILD_PATH, { force: true, recursive: true }); +fs.rmSync(paths.DIST_PATH, { force: true, recursive: true }); +fs.mkdirSync(BUILD_PATH, { recursive: true }); +fs.mkdirSync(paths.DIST_PATH, { recursive: true }); const MDNS_BINDING_PATH = path.join( __dirname, @@ -81,10 +93,10 @@ async function build() { * https://mdn.io/Native_manifests#Native_messaging_manifests */ const manifest = { - name: meta.__applicationName, + name: config.applicationName, description: "", type: "stdio", - allowed_extensions: [EXTENSION_ID] + allowed_extensions: [config.extensionId] }; /** @@ -105,7 +117,7 @@ async function build() { }; const executableName = paths.getExecutableName(process.platform); - const executablePath = paths.getExecutablePath( + const executablePath = paths.getExecutableDirectory( process.platform, argv.arch ); @@ -132,7 +144,7 @@ async function build() { path.join(BUILD_PATH, MDNS_BINDING_NAME) ); - fs.removeSync(path.join(BUILD_PATH, "src")); + fs.rmSync(path.join(BUILD_PATH, "src")); manifest.path = !argv.package && argv.usePkg @@ -141,7 +153,7 @@ async function build() { } else { let launcherPath = path.join( BUILD_PATH, - meta.__applicationExecutableName + config.applicationExecutableName ); const modulesDir = path.join(ROOT_PATH, "node_modules"); @@ -209,36 +221,42 @@ NODE_PATH="${modulesDir}" node $(dirname $0)/src/main.js --__name $(basename $0) } // Remove build directory - fs.removeSync(BUILD_PATH); + fs.rmSync(BUILD_PATH, { force: true, recursive: true }); } /** * Takes a platform and returns the path of the created * installer package. + * + * @param {string} platform + * @param {string} arch */ async function packageApp(platform, arch) { - const packageFunctionArgs = [ + /** @type {[ string, string, string, string ]} */ + const packageFnArgs = [ arch, - // platformExecutableName - paths.getExecutableName(platform, arch), - // platformExecutablePath - paths.getExecutablePath(platform, arch), - // platformManifestPath - paths.getManifestPath(platform, arch, argv.packageType) + paths.getExecutableName(platform), + paths.getExecutableDirectory(platform, arch), + paths.getManifestDirectory(platform, arch, argv.packageType) ]; switch (platform) { case "win32": - return packageWin32(...packageFunctionArgs); + // Pass without manifest + return packageWin32( + packageFnArgs[0], + packageFnArgs[1], + packageFnArgs[2] + ); case "darwin": - return packageDarwin(...packageFunctionArgs); + return packageDarwin(...packageFnArgs); case "linux": { switch (argv.packageType) { case "deb": - return packageLinuxDeb(...packageFunctionArgs); + return packageLinuxDeb(...packageFnArgs); case "rpm": - return packageLinuxRpm(...packageFunctionArgs); + return packageLinuxRpm(...packageFnArgs); } break; @@ -258,52 +276,63 @@ async function packageApp(platform, arch) { * * Requires the pkgbuild and productbuild command line * utilities. Only possible on macOS. + * + * @param {string} arch + * @param {string} platformExecutableName + * @param {string} platformExecutableDirectory + * @param {string} platformManifestDirectory */ function packageDarwin( arch, platformExecutableName, - platformExecutablePath, - platformManifestPath + platformExecutableDirectory, + platformManifestDirectory ) { - const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.pkg`; - const componentName = `${meta.__applicationName}_component.pkg`; + const outputName = `${config.applicationName}-${config.applicationVersion}-${arch}.pkg`; + const componentName = `${config.applicationName}_component.pkg`; const packagingDir = path.join(__dirname, "../packaging/mac/"); const packagingOutputDir = path.join(BUILD_PATH, "packaging"); // Create pkgbuild root const rootPath = path.join(BUILD_PATH, "root"); - const rootExecutablePath = path.join(rootPath, platformExecutablePath); - const rootManifestPath = path.join(rootPath, platformManifestPath); + const rootExecutableDirectory = path.join( + rootPath, + platformExecutableDirectory + ); + const rootManifestDirectory = path.join( + rootPath, + platformManifestDirectory + ); // Create install locations - fs.ensureDirSync(rootExecutablePath, { recursive: true }); - fs.ensureDirSync(rootManifestPath, { recursive: true }); + fs.mkdirSync(rootExecutableDirectory, { recursive: true }); + fs.mkdirSync(rootManifestDirectory, { recursive: true }); // Move files to root fs.moveSync( path.join(BUILD_PATH, platformExecutableName), - path.join(rootExecutablePath, platformExecutableName) + path.join(rootExecutableDirectory, platformExecutableName) ); fs.moveSync( path.join(BUILD_PATH, MDNS_BINDING_NAME), - path.join(rootExecutablePath, MDNS_BINDING_NAME) + path.join(rootExecutableDirectory, MDNS_BINDING_NAME) ); fs.moveSync( path.join(BUILD_PATH, paths.MANIFEST_NAME), - path.join(rootManifestPath, paths.MANIFEST_NAME) + path.join(rootManifestDirectory, paths.MANIFEST_NAME) ); // Copy static files to be processed fs.copySync(packagingDir, packagingOutputDir); const view = { - applicationName: meta.__applicationName, + applicationName: config.applicationName, manifestName: paths.MANIFEST_NAME, componentName, - packageId: `tf.matt.${meta.__applicationName}`, - executablePath: platformExecutablePath, - manifestPath: platformManifestPath + packageId: `tf.matt.${config.applicationName}`, + executablePath: platformExecutableDirectory, + manifestPath: platformManifestDirectory }; // Template paths @@ -321,8 +350,8 @@ function packageDarwin( // Build component package spawnSync( `pkgbuild --root ${rootPath} \ - --identifier "tf.matt.${meta.__applicationName}" \ - --version "${meta.__applicationVersion}" \ + --identifier "tf.matt.${config.applicationName}" \ + --version "${config.applicationVersion}" \ --scripts ${path.join(packagingOutputDir, "scripts")} \ ${path.join(BUILD_PATH, componentName)}`, spawnOptions @@ -350,35 +379,46 @@ function packageDarwin( * (packaging/linux/deb/DEBIAN/control) to root, then builds * package from root. * Requires the dpkg-deb command line utility. + * + * @param {string} arch + * @param {string} platformExecutableName + * @param {string} platformExecutableDirectory + * @param {string} platformManifestDirectory */ function packageLinuxDeb( arch, platformExecutableName, - platformExecutablePath, - platformManifestPath + platformExecutableDirectory, + platformManifestDirectory ) { - const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.deb`; + const outputName = `${config.applicationName}-${config.applicationVersion}-${arch}.deb`; // Create root const rootPath = path.join(BUILD_PATH, "root"); - const rootExecutablePath = path.join(rootPath, platformExecutablePath); - const rootManifestPath = path.join(rootPath, platformManifestPath); + const rootExecutableDirectory = path.join( + rootPath, + platformExecutableDirectory + ); + const rootManifestDirectory = path.join( + rootPath, + platformManifestDirectory + ); - fs.ensureDirSync(rootExecutablePath, { recursive: true }); - fs.ensureDirSync(rootManifestPath, { recursive: true }); + fs.mkdirSync(rootExecutableDirectory, { recursive: true }); + fs.mkdirSync(rootManifestDirectory, { recursive: true }); // Move files to root fs.moveSync( path.join(BUILD_PATH, platformExecutableName), - path.join(rootExecutablePath, platformExecutableName) + path.join(rootExecutableDirectory, platformExecutableName) ); fs.moveSync( path.join(BUILD_PATH, MDNS_BINDING_NAME), - path.join(rootExecutablePath, MDNS_BINDING_NAME) + path.join(rootExecutableDirectory, MDNS_BINDING_NAME) ); fs.moveSync( path.join(BUILD_PATH, paths.MANIFEST_NAME), - path.join(rootManifestPath, paths.MANIFEST_NAME) + path.join(rootManifestDirectory, paths.MANIFEST_NAME) ); const controlDir = path.join(__dirname, "../packaging/linux/deb/DEBIAN/"); @@ -390,10 +430,10 @@ function packageLinuxDeb( const view = { // Debian package names can't contain underscores - packageName: meta.__applicationName.replace(/_/g, "-"), - applicationName: meta.__applicationName, - applicationVersion: meta.__applicationVersion, - author + packageName: config.applicationName.replace(/_/g, "-"), + applicationName: config.applicationName, + applicationVersion: config.applicationVersion, + author: config.author }; // Do templating on control file @@ -418,14 +458,19 @@ function packageLinuxDeb( * Templates and uses the spec file * (packaging/linux/rpm/package.spec) to build the package. * Requires the rpmbuild command line utility. + * + * @param {string} arch + * @param {string} platformExecutableName + * @param {string} platformExecutableDirectory + * @param {string} platformManifestDirectory */ function packageLinuxRpm( arch, platformExecutableName, - platformExecutablePath, - platformManifestPath + platformExecutableDirectory, + platformManifestDirectory ) { - const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.rpm`; + const outputName = `${config.applicationName}-${config.applicationVersion}-${arch}.rpm`; const specPath = path.join( __dirname, @@ -435,11 +480,11 @@ function packageLinuxRpm( const specOutputPath = path.join(BUILD_PATH, path.basename(specPath)); const view = { - packageName: meta.__applicationName, - applicationName: meta.__applicationName, - applicationVersion: meta.__applicationVersion, - executablePath: platformExecutablePath, - manifestPath: platformManifestPath, + packageName: config.applicationName, + applicationName: config.applicationName, + applicationVersion: config.applicationVersion, + executablePath: platformExecutableDirectory, + manifestPath: platformManifestDirectory, executableName: platformExecutableName, manifestName: paths.MANIFEST_NAME, bindingName: MDNS_BINDING_NAME @@ -470,18 +515,26 @@ function packageLinuxRpm( * Uses NSIS to create a GUI installer with an installer * script (packaging/win/installer.nsi). Requires the * makensis command line utility. + * + * @param {string} arch + * @param {string} platformExecutableName + * @param {string} platformExecutableDirectory */ -function packageWin32(arch, platformExecutableName, platformExecutablePath) { - const outputName = `${meta.__applicationName}-${meta.__applicationVersion}-${arch}.exe`; +function packageWin32( + arch, + platformExecutableName, + platformExecutableDirectory +) { + const outputName = `${config.applicationName}-${config.applicationVersion}-${arch}.exe`; const scriptPath = path.join(__dirname, "../packaging/win/installer.nsi"); const scriptOutputPath = path.join(BUILD_PATH, path.basename(scriptPath)); const view = { - applicationName: meta.__applicationName, - applicationVersion: meta.__applicationVersion, + applicationName: config.applicationName, + applicationVersion: config.applicationVersion, executableName: platformExecutableName, - executablePath: platformExecutablePath, + executablePath: platformExecutableDirectory, manifestName: paths.MANIFEST_NAME, bindingName: MDNS_BINDING_NAME, winRegistryKey: paths.REGISTRY_KEY, @@ -489,8 +542,8 @@ function packageWin32(arch, platformExecutableName, platformExecutablePath) { licensePath: paths.LICENSE_PATH, // Uninstaller keys - registryPublisher: author, - registryUrlInfoAbout: homepage + registryPublisher: config.author, + registryUrlInfoAbout: config.homepageUrl }; // Write templated script to build dir diff --git a/app/bin/install-manifest.js b/app/bin/install-manifest.js index 482ad3b..c589338 100644 --- a/app/bin/install-manifest.js +++ b/app/bin/install-manifest.js @@ -1,69 +1,77 @@ -const fs = require("fs-extra"); -const os = require("os"); -const path = require("path"); -const minimist = require("minimist"); +// @ts-check -const paths = require("./lib/paths"); +import fs from "fs-extra"; +import os from "os"; +import path from "path"; +import { spawnSync } from "child_process"; -const argv = minimist(process.argv.slice(2), { - boolean: ["remove"], - default: { - remove: false - } -}); +import yargs from "yargs"; -const CURRENT_MANIFEST_PATH = path.join(paths.DIST_PATH, paths.MANIFEST_NAME); +import * as paths from "./lib/paths.js"; -if (!fs.existsSync(CURRENT_MANIFEST_PATH) && !argv.remove) { - console.error("No manifest in dist/app/ to install."); +const argv = yargs() + .help() + .version(false) + .option("remove", { + describe: "Uninstall manifest", + type: "boolean" + }) + .parseSync(process.argv); + +// Path to newly-built manifest +const newManifestPath = path.join(paths.DIST_PATH, paths.MANIFEST_NAME); +if (!fs.existsSync(newManifestPath) && !argv.remove) { + console.error("Error: No manifest to install!"); process.exit(1); } -const platform = os.platform(); -const arch = os.arch(); +console.info(`${argv.remove ? "Uninstalling" : "Installing"} manifest... `); +const platform = os.platform(); switch (platform) { + // File-based manifests case "darwin": case "linux": { - // Manifest location within home directory - const destination = path.join( + // User-specific manifest within home directory + const manifestDirectory = path.join( os.homedir(), platform === "linux" - ? ".mozilla/native-messaging-hosts/" - : paths.getManifestPath(platform, arch) + ? ".mozilla/native-messaging-hosts" + : paths.getManifestDirectory(platform, os.arch()) ); + const manifestPath = path.join(manifestDirectory, paths.MANIFEST_NAME); + if (argv.remove) { - fs.remove(path.join(destination, paths.MANIFEST_NAME)); - break; + // Uninstall manifest + fs.rmSync(manifestPath); + } else { + // Install manifest + fs.mkdirSync(manifestDirectory, { recursive: true }); + fs.copyFileSync(newManifestPath, manifestPath); } - // Install manifest - fs.ensureDirSync(destination); - fs.copyFileSync( - CURRENT_MANIFEST_PATH, - path.join(destination, paths.MANIFEST_NAME) - ); - break; } case "win32": { - const { Registry } = require("rage-edit"); - const REGISTRY_PATH = `HKCU\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${paths.REGISTRY_KEY}`; + const registryKey = `HKCU\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${paths.REGISTRY_KEY}`; - if (argv.remove) { - Registry.delete(REGISTRY_PATH); - break; - } - - Registry.set(REGISTRY_PATH, "", CURRENT_MANIFEST_PATH, "REG_SZ"); + // Call reg command + spawnSync( + argv.remove + ? `reg delete ${registryKey} /f` + : `reg add ${registryKey} /ve /d "${newManifestPath}" /f`, + { + shell: true, + stdio: [process.stdin, process.stdout, process.stderr] + } + ); break; } - default: { - console.error("Sorry, this installer does not yet support your OS"); + default: + console.error("Error: Unsupported platform!"); process.exit(1); - } } diff --git a/app/bin/lib/paths.js b/app/bin/lib/paths.js index cba279c..88ac735 100644 --- a/app/bin/lib/paths.js +++ b/app/bin/lib/paths.js @@ -1,85 +1,98 @@ -"use strict"; +// @ts-check -const path = require("path"); +import path from "path"; +import url from "url"; -const { - __applicationName, - __applicationDirectoryName, - __applicationExecutableName -} = require("../../package.json"); +import config from "../../config.json" assert { type: "json" }; +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); const rootPath = path.join(__dirname, "../../../"); -exports.DIST_PATH = path.join(rootPath, "dist/app"); -exports.LICENSE_PATH = path.join(rootPath, "LICENSE"); +export const DIST_PATH = path.join(rootPath, "dist/app"); +export const LICENSE_PATH = path.join(rootPath, "LICENSE"); -exports.REGISTRY_KEY = __applicationName; +export const REGISTRY_KEY = config.applicationName; -exports.pkgPlatformMap = { +export const pkgPlatformMap = { win32: "win", darwin: "macos", linux: "linux" }; -exports.MANIFEST_NAME = `${__applicationName}.json`; +export const MANIFEST_NAME = `${config.applicationName}.json`; -exports.getExecutableName = platform => { +/** + * @param {string} platform + * @returns {string} + */ +export function getExecutableName(platform) { switch (platform) { case "win32": - return `${__applicationExecutableName}.exe`; + return `${config.applicationExecutableName}.exe`; case "darwin": case "linux": - return __applicationExecutableName; + return config.applicationExecutableName; } -}; -exports.getExecutablePath = (platform, arch) => { - const EXECUTABLE_PATH_WIN32_X64 = `C:\\Program Files\\${__applicationDirectoryName}\\`; - const EXECUTABLE_PATH_WIN32_X86 = `C:\\Program Files (x86)\\${__applicationDirectoryName}\\`; - const EXECUTABLE_PATH_DARWIN = `/Library/Application Support/${__applicationDirectoryName}/`; - const EXECUTABLE_PATH_LINUX = `/opt/${__applicationDirectoryName}/`; + throw new Error("No executable name for specified platform!"); +} + +/** + * @param {string} platform + * @param {string} arch + * @returns {string} + */ +export function getExecutableDirectory(platform, arch) { + const EXECUTABLE_DIR_WIN32_X64 = `C:\\Program Files\\${config.applicationDirectoryName}\\`; + const EXECUTABLE_DIR_WIN32_X86 = `C:\\Program Files (x86)\\${config.applicationDirectoryName}\\`; + const EXECUTABLE_DIR_DARWIN = `/Library/Application Support/${config.applicationDirectoryName}/`; + const EXECUTABLE_DIR_LINUX = `/opt/${config.applicationDirectoryName}/`; switch (platform) { case "win32": switch (arch) { case "x86": - return EXECUTABLE_PATH_WIN32_X86; + return EXECUTABLE_DIR_WIN32_X86; case "x64": - return EXECUTABLE_PATH_WIN32_X64; + return EXECUTABLE_DIR_WIN32_X64; } break; case "darwin": - return EXECUTABLE_PATH_DARWIN; + return EXECUTABLE_DIR_DARWIN; case "linux": - return EXECUTABLE_PATH_LINUX; + return EXECUTABLE_DIR_LINUX; } -}; -exports.getManifestPath = (platform, arch, linuxPackageType) => { - const MANIFEST_PATH_DARWIN = + throw new Error("No executable directory for specified platform!"); +} + +/** + * @param {string} platform + * @param {string} arch + * @param {string} [linuxPackageType] + * @returns {string} + */ +export function getManifestDirectory(platform, arch, linuxPackageType) { + const MANIFEST_DIR_DARWIN = "/Library/Application Support/Mozilla/NativeMessagingHosts/"; - const MANIFEST_PATH_LINUX_DEB = "/usr/lib/mozilla/native-messaging-hosts/"; - const MANIFEST_PATH_LINUX_RPM = - "/usr/lib64/mozilla/native-messaging-hosts/"; + const MANIFEST_DIR_LINUX_DEB = "/usr/lib/mozilla/native-messaging-hosts/"; + const MANIFEST_DIR_LINUX_RPM = "/usr/lib64/mozilla/native-messaging-hosts/"; switch (platform) { case "win32": - switch (arch) { - case "x86": - case "x64": - return exports.getExecutablePath(platform, arch); - } - break; + return getExecutableDirectory(platform, arch); case "darwin": - return MANIFEST_PATH_DARWIN; + return MANIFEST_DIR_DARWIN; case "linux": switch (linuxPackageType) { case "deb": - return MANIFEST_PATH_LINUX_DEB; + return MANIFEST_DIR_LINUX_DEB; case "rpm": - return MANIFEST_PATH_LINUX_RPM; + return MANIFEST_DIR_LINUX_RPM; } break; } -}; + + throw new Error("No manifest directory for specified platform!"); +} diff --git a/app/config.json b/app/config.json new file mode 100644 index 0000000..96c941d --- /dev/null +++ b/app/config.json @@ -0,0 +1,9 @@ +{ + "author": "Matt Hensman ", + "homepageUrl": "https://hensm.github.io/fx_cast", + "applicationName": "fx_cast_bridge", + "applicationVersion": "0.2.0", + "applicationDirectoryName": "fx_cast", + "applicationExecutableName": "fx_cast_bridge", + "extensionId": "fx_cast@matt.tf" +} diff --git a/app/package-lock.json b/app/package-lock.json index 0c0eb83..c856a73 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -11,10 +11,10 @@ "fast-srp-hap": "^2.0.4", "mdns": "^2.7.2", "mime-types": "^2.1.35", - "minimist": "^1.2.6", "node-fetch": "^3.2.3", "tweetnacl": "^1.0.3", - "ws": "^8.5.0" + "ws": "^8.5.0", + "yargs": "^17.5.1" }, "devDependencies": { "@types/mdns": "^0.0.34", @@ -23,14 +23,12 @@ "@types/node": "^17.0.26", "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.3", + "@types/yargs": "^17.0.11", "fs-extra": "^10.1.0", "mustache": "^4.2.0", "pkg": "^5.6.0", "tiny-typed-emitter": "^2.1.0", "typescript": "^4.6.3" - }, - "optionalDependencies": { - "rage-edit": "^1.2.0" } }, "node_modules/@babel/helper-validator-identifier": { @@ -206,6 +204,21 @@ "@types/node": "*" } }, + "node_modules/@types/yargs": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", + "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -231,7 +244,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -430,7 +442,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -441,7 +452,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -450,7 +460,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -459,7 +468,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -473,7 +481,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -494,7 +501,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -505,8 +511,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -625,8 +630,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/end-of-stream": { "version": "1.4.4", @@ -641,7 +645,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -862,7 +865,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -1176,7 +1178,8 @@ "node_modules/minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true }, "node_modules/mkdirp-classic": { "version": "0.5.3", @@ -1445,6 +1448,15 @@ "pkg-fetch": "lib-es5/bin.js" } }, + "node_modules/pkg-fetch/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pkg-fetch/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -1460,6 +1472,15 @@ "node": ">=10" } }, + "node_modules/pkg-fetch/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pkg-fetch/node_modules/node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -1480,6 +1501,59 @@ } } }, + "node_modules/pkg-fetch/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-fetch/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-fetch/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pkg-fetch/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/pkg/node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -1601,12 +1675,6 @@ } ] }, - "node_modules/rage-edit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rage-edit/-/rage-edit-1.2.0.tgz", - "integrity": "sha512-0RspBRc2s6We4g7hRCvT5mu7YPEnfjvQK8Tt354a2uUNJCMC7MKLvo/1mLvHUCQ/zbP6siQyp5VRZN7UCpMFZg==", - "optional": true - }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -1641,7 +1709,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -2048,7 +2115,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -2065,7 +2131,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2074,7 +2139,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2083,7 +2147,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2097,7 +2160,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2135,7 +2197,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -2147,37 +2208,34 @@ "dev": true }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs/node_modules/ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2186,7 +2244,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -2195,7 +2252,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2209,7 +2265,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -2371,6 +2426,21 @@ "@types/node": "*" } }, + "@types/yargs": { + "version": "17.0.11", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.11.tgz", + "integrity": "sha512-aB4y9UDUXTSMxmM4MH+YnuR0g5Cph3FLQBoWoMB21DSvFVAxRVEHEMx3TLh+zUZYMCQtKiqazz0Q4Rre31f/OA==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, "agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -2390,7 +2460,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } @@ -2533,7 +2602,6 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -2543,20 +2611,17 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -2567,7 +2632,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -2584,7 +2648,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } @@ -2592,8 +2655,7 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "combined-stream": { "version": "1.0.8", @@ -2680,8 +2742,7 @@ "emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "end-of-stream": { "version": "1.4.4", @@ -2695,8 +2756,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escodegen": { "version": "2.0.0", @@ -2857,8 +2917,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "github-from-package": { "version": "0.0.0", @@ -3086,7 +3145,8 @@ "minimist": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true }, "mkdirp-classic": { "version": "0.5.3", @@ -3295,6 +3355,12 @@ "yargs": "^16.2.0" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", @@ -3307,6 +3373,12 @@ "universalify": "^2.0.0" } }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, "node-fetch": { "version": "2.6.7", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", @@ -3315,6 +3387,47 @@ "requires": { "whatwg-url": "^5.0.0" } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } }, @@ -3393,12 +3506,6 @@ "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true }, - "rage-edit": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/rage-edit/-/rage-edit-1.2.0.tgz", - "integrity": "sha512-0RspBRc2s6We4g7hRCvT5mu7YPEnfjvQK8Tt354a2uUNJCMC7MKLvo/1mLvHUCQ/zbP6siQyp5VRZN7UCpMFZg==", - "optional": true - }, "rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -3429,8 +3536,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" }, "resolve": { "version": "1.22.0", @@ -3731,7 +3837,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "requires": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -3741,20 +3846,17 @@ "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3765,7 +3867,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -3787,8 +3888,7 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "4.0.0", @@ -3797,37 +3897,33 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "dependencies": { "ansi-regex": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" }, "is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" }, "string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "requires": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -3838,7 +3934,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "requires": { "ansi-regex": "^5.0.1" } @@ -3846,10 +3941,9 @@ } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" } } } diff --git a/app/package.json b/app/package.json index bf4f5c4..49c714f 100644 --- a/app/package.json +++ b/app/package.json @@ -1,8 +1,5 @@ { - "__applicationName": "fx_cast_bridge", - "__applicationVersion": "0.2.0", - "__applicationDirectoryName": "fx_cast", - "__applicationExecutableName": "fx_cast_bridge", + "type": "module", "scripts": { "build": "node bin/build.js", "package": "node bin/build.js --package", @@ -16,10 +13,10 @@ "fast-srp-hap": "^2.0.4", "mdns": "^2.7.2", "mime-types": "^2.1.35", - "minimist": "^1.2.6", "node-fetch": "^3.2.3", "tweetnacl": "^1.0.3", - "ws": "^8.5.0" + "ws": "^8.5.0", + "yargs": "^17.5.1" }, "devDependencies": { "@types/mdns": "^0.0.34", @@ -28,13 +25,11 @@ "@types/node": "^17.0.26", "@types/node-fetch": "^2.6.1", "@types/ws": "^8.5.3", + "@types/yargs": "^17.0.11", "fs-extra": "^10.1.0", "mustache": "^4.2.0", "pkg": "^5.6.0", "tiny-typed-emitter": "^2.1.0", "typescript": "^4.6.3" - }, - "optionalDependencies": { - "rage-edit": "^1.2.0" } } diff --git a/app/src/bridge/index.ts b/app/src/bridge/index.ts index 8c6b693..c63d94d 100755 --- a/app/src/bridge/index.ts +++ b/app/src/bridge/index.ts @@ -6,7 +6,7 @@ import { handleCastMessage } from "./components/cast"; import { startDiscovery, stopDiscovery } from "./components/discovery"; import { startMediaServer, stopMediaServer } from "./components/mediaServer"; -import { __applicationVersion } from "../../package.json"; +import { applicationVersion } from "../../config.json"; process.on("SIGTERM", () => { stopDiscovery(); @@ -24,7 +24,7 @@ messaging.on("message", (message: Message) => { switch (message.subject) { case "bridge:getInfo": case "bridge:/getInfo": { - messaging.send(__applicationVersion); + messaging.send(applicationVersion); break; } diff --git a/app/src/daemon.ts b/app/src/daemon.ts index eb20f6b..f828375 100644 --- a/app/src/daemon.ts +++ b/app/src/daemon.ts @@ -6,24 +6,28 @@ import WebSocket from "ws"; import { spawn } from "child_process"; import { Readable } from "stream"; -import { DecodeTransform, EncodeTransform } from "./transforms"; +import { DecodeTransform, EncodeTransform } from "./transforms.js"; interface DaemonOpts { host: string; port: number; - password: string; + password?: string; } export function init(opts: DaemonOpts) { const server = http.createServer(); const wss = new WebSocket.Server({ noServer: true }); - process.stdout.write("Starting WebSocket server... "); + process.stdout.write( + `Starting WebSocket server at ws://${ + opts.host.includes(":") ? `[${opts.host}]` : opts.host + }:${opts.port}... ` + ); server.on("listening", () => { process.stdout.write("Done!\n"); }); - wss.on("error", err => { + server.on("error", err => { console.error("Failed!"); console.error(err.message); }); diff --git a/app/src/main.ts b/app/src/main.ts index 1ab3eaa..0fe8455 100644 --- a/app/src/main.ts +++ b/app/src/main.ts @@ -1,64 +1,55 @@ "use strict"; -import path from "path"; -import minimist from "minimist"; -import { __applicationVersion } from "../package.json"; +import yargs from "yargs"; +import { applicationName, applicationVersion } from "../config.json"; -const argv = minimist(process.argv.slice(2), { - boolean: ["daemon", "help", "version"], - string: ["__name", "host", "port", "password"], - alias: { - d: "daemon", - h: "help", - v: "version", - n: "host", - p: "port", - P: "password" - }, - default: { - __name: path.basename(process.argv[0]), - daemon: false, - host: "localhost", - port: "9556" - } -}); +const argv = yargs() + .scriptName(applicationName) + .usage("$0 [args]") + .help() + .alias("help", "h") + .version(`v${applicationVersion}`) + .alias("version", "v") + .option("daemon", { + alias: "d", + describe: `Launch in daemon mode. This starts a WebSocket server that \ +the extension can be configured to connect to under bridge options.`, + type: "boolean" + }) + .option("host", { + alias: "n", + describe: `Host for daemon WebSocket server. This must match the host \ +set in the extension options.`, + default: "localhost" + }) + .option("port", { + alias: "p", + describe: `Port number for daemon WebSocket server. This must match \ +the port set in the extension options.`, + default: 9556 + }) + .option("password", { + alias: "P", + describe: `Set an optional password for the daemon WebSocket server. \ +This must match the password set in the extension options. +WARNING: This password is intended only as a basic access control measure and \ +is transmitted in plain text even over remote connections!`, + type: "string" + }) + .check(argv => { + if (argv.port < 1025 || argv.port > 65535) { + throw new Error("Invalid port specified!"); + } -if (argv.version) { - // eslint-disable-next-line no-console - console.log(`v${__applicationVersion}`); -} else if (argv.help) { - // eslint-disable-next-line no-console - console.log( - `Usage: ${argv.__name} [options] - -Options: - -h, --help Print usage info - -v, --version Print version info - -d, --daemon Launch in daemon mode. This starts a WebSocket server that - the extension can be configured to connect to under bridge - options. - -n, --host Host for daemon WebSocket server. This must match the host - set in the extension options. - -p, --port Port number for daemon WebSocket server. This must match the - port set in the extension options. - -P, --password Set an optional password for the daemon WebSocket server. - This must match the password set in the extension options. - WARNING: This password is intended only as a basic access - control measure and is transmitted in plain text even over - remote connections! -` - ); -} else if (argv.daemon) { - const port = parseInt(argv.port); - if (!port || port < 1025 || port > 65535) { - console.error("Invalid port specified!"); - process.exit(1); - } + return true; + }) + .parseSync(process.argv); +if (argv.daemon) { import("./daemon").then(daemon => { daemon.init({ host: argv.host, - port, + port: argv.port, password: argv.password }); }); diff --git a/app/tsconfig.json b/app/tsconfig.json index 72896a1..9324218 100644 --- a/app/tsconfig.json +++ b/app/tsconfig.json @@ -1,10 +1,7 @@ { - "extends": "../tsconfig" - , "include": [ - "./src/**/*" - , "./@types/**/*" - ] - , "compilerOptions": { - "lib": [ "ES2020.String", "DOM" ] + "extends": "../tsconfig", + "include": ["./src/**/*", "./@types/**/*"], + "compilerOptions": { + "lib": ["ES2020.String", "DOM"] } } diff --git a/ext/bin/build.js b/ext/bin/build.js index 0e7af3e..9d78724 100644 --- a/ext/bin/build.js +++ b/ext/bin/build.js @@ -1,45 +1,50 @@ // @ts-check -"use strict"; -const fs = require("fs-extra"); -const path = require("path"); +import fs from "fs-extra"; +import path from "path"; +import url from "url"; -const esbuild = require("esbuild"); -const minimist = require("minimist"); -const sveltePlugin = require("esbuild-svelte"); -const sveltePreprocess = require("svelte-preprocess"); -const webExt = require("web-ext"); +import esbuild from "esbuild"; +import sveltePlugin from "esbuild-svelte"; +import sveltePreprocess from "svelte-preprocess"; +import yargs from "yargs"; +import webExt from "web-ext"; -const { copyFilesPlugin } = require("./lib/copyFilesPlugin.js"); +import copyFilesPlugin from "./lib/copyFilesPlugin.js"; const BRIDGE_NAME = "fx_cast_bridge"; const BRIDGE_VERSION = "0.2.0"; const MIRRORING_APP_ID = "19A6F4AE"; -const argv = minimist(process.argv.slice(2), { - boolean: ["package", "watch"], - string: ["mirroringAppId", "mode"], - default: { - package: false, - watch: false, - mirroringAppId: MIRRORING_APP_ID, - mode: "development" - } -}); - -if (argv.package && argv.watch) { - console.error("Cannot package whilst watching files."); - process.exit(1); -} +const argv = yargs() + .help() + .version(false) + .option("watch", { + describe: "Rebuild on changes", + type: "boolean" + }) + .option("package", { + describe: "Package with web-ext", + type: "boolean", + conflicts: "watch" + }) + .option("mode", { + describe: "Set build mode", + choices: ["development", "production"], + default: "development" + }) + .parseSync(process.argv); // If packaging, use production mode if (argv.package) { argv.mode = "production"; } +const __dirname = path.dirname(url.fileURLToPath(import.meta.url)); + // Paths -const rootPath = path.resolve(__dirname, "../"); +const rootPath = path.join(__dirname, "../"); const srcPath = path.join(rootPath, "src"); const distPath = path.join(rootPath, "../dist/ext/"); @@ -75,7 +80,7 @@ const buildOpts = { define: { BRIDGE_NAME: `"${BRIDGE_NAME}"`, BRIDGE_VERSION: `"${BRIDGE_VERSION}"`, - MIRRORING_APP_ID: `"${argv.mirroringAppId}"` + MIRRORING_APP_ID: `"${MIRRORING_APP_ID}"` }, plugins: [ // @ts-ignore diff --git a/ext/bin/lib/copyFilesPlugin.js b/ext/bin/lib/copyFilesPlugin.js index 7e68cf5..7fa7408 100644 --- a/ext/bin/lib/copyFilesPlugin.js +++ b/ext/bin/lib/copyFilesPlugin.js @@ -1,11 +1,11 @@ // @ts-check "use strict"; -const path = require("path"); -const fs = require("fs"); +import path from "path"; +import fs from "fs"; // eslint-disable-next-line no-unused-vars -const esbuild = require("esbuild"); +import esbuild from "esbuild"; /** * Walks file tree from a given root path. @@ -37,17 +37,14 @@ function* walk(rootPath) { * * @type {(opts: CopyFilesPluginOpts) => esbuild.Plugin} */ -exports.copyFilesPlugin = opts => { +export default opts => { if (!fs.existsSync(opts.src)) { throw new Error("copyFilesPlugin: src path not found!"); } - const matchingPaths = []; - for (const path of walk(opts.src)) { - if (!opts.excludePattern?.test(path)) { - matchingPaths.push(path); - } - } + const matchingPaths = [...walk(opts.src)].filter( + path => !opts.excludePattern?.test(path) + ); return { name: "copy-files", diff --git a/ext/package-lock.json b/ext/package-lock.json index 140c07e..10d2e89 100644 --- a/ext/package-lock.json +++ b/ext/package-lock.json @@ -17,7 +17,8 @@ "ts-loader": "^9.2.8", "typescript": "^4.6.3", "uuid": "^8.3.2", - "web-ext": "^6.8.0" + "web-ext": "^6.8.0", + "yargs": "^17.5.1" } }, "node_modules/@babel/code-frame": { @@ -753,15 +754,6 @@ "node": ">=12" } }, - "node_modules/addons-linter/node_modules/yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true, - "engines": { - "node": ">=12" - } - }, "node_modules/addons-moz-compare": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/addons-moz-compare/-/addons-moz-compare-1.2.0.tgz", @@ -7433,6 +7425,33 @@ "npm": ">=6.9.0" } }, + "node_modules/web-ext/node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/web-ext/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, "node_modules/webpack": { "version": "5.72.0", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.0.tgz", @@ -7690,30 +7709,30 @@ "dev": true }, "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, "engines": { - "node": ">=10" + "node": ">=12" } }, "node_modules/yauzl": { @@ -8390,12 +8409,6 @@ "y18n": "^5.0.5", "yargs-parser": "^21.0.0" } - }, - "yargs-parser": { - "version": "21.0.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", - "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", - "dev": true } } }, @@ -13452,6 +13465,29 @@ "ws": "7.4.6", "yargs": "16.2.0", "zip-dir": "2.0.0" + }, + "dependencies": { + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true + } } }, "webpack": { @@ -13639,24 +13675,24 @@ "dev": true }, "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { "cliui": "^7.0.2", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "string-width": "^4.2.0", + "string-width": "^4.2.3", "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yargs-parser": "^21.0.0" } }, "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true }, "yauzl": { diff --git a/ext/package.json b/ext/package.json index b4e6009..1ad43b0 100644 --- a/ext/package.json +++ b/ext/package.json @@ -1,4 +1,5 @@ { + "type": "module", "scripts": { "build": "node bin/build.js", "package": "node bin/build.js --package", @@ -19,6 +20,7 @@ "ts-loader": "^9.2.8", "typescript": "^4.6.3", "uuid": "^8.3.2", - "web-ext": "^6.8.0" + "web-ext": "^6.8.0", + "yargs": "^17.5.1" } } diff --git a/package-lock.json b/package-lock.json index 32b5117..a0284c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,6 @@ "fs-extra": "^10.0.1", "glob": "^7.2.0", "jasmine-console-reporter": "^3.1.0", - "minimist": "^1.2.5", "prettier": "^2.5.1", "prettier-plugin-svelte": "^2.7.0", "selenium-webdriver": "^4.1.1", @@ -1374,12 +1373,6 @@ "node": "*" } }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -3056,12 +3049,6 @@ "brace-expansion": "^1.1.7" } }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", diff --git a/package.json b/package.json index 29c2b37..aa2de61 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,4 @@ { - "author": "Matt Hensman ", - "homepage": "https://hensm.github.io/fx_cast", - "bugs": "https://github.com/hensm/fx_cast", "scripts": { "postinstall": "npm run postinstall:app && npm run postinstall:ext", "postinstall:app": "cd app && npm install", @@ -30,7 +27,6 @@ "fs-extra": "^10.0.1", "glob": "^7.2.0", "jasmine-console-reporter": "^3.1.0", - "minimist": "^1.2.5", "prettier": "^2.5.1", "prettier-plugin-svelte": "^2.7.0", "selenium-webdriver": "^4.1.1",