nw-builder 4.19.1 → 4.20.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -98,7 +98,7 @@ See `nw-builder` in action by building the demo application.
98
98
 
99
99
  ## Concepts
100
100
 
101
- `nw-builder` can get, run and build NW.js applications. We refer to them as get, run and build modes.
101
+ `nw-builder` can get, run, build and package NW.js applications. We refer to them as get, run, build and package modes.
102
102
 
103
103
  ### Get Mode
104
104
 
@@ -184,13 +184,33 @@ nwbuild({
184
184
  });
185
185
  ```
186
186
 
187
+ ### Package Mode
188
+
189
+ Builds the application, then packages the `outDir` produced by the build via
190
+ [`@nwutils/packager`](https://www.npmjs.com/package/@nwutils/packager). `mode: "package"` resolves with the path to the resulting packaged artifact instead of `undefined`.
191
+
192
+ ```javascript
193
+ const packagePath = await nwbuild({
194
+ mode: "package",
195
+ });
196
+ ```
197
+
198
+ `format` selects the packager to run and defaults to `"AppImage"` on Linux. Only `"AppImage"` is implemented today - `deb`, `rpm`, `msix`, `nsis` and `dmg` are reserved for later.
199
+
200
+ ```javascript
201
+ const appImagePath = await nwbuild({
202
+ mode: "package",
203
+ format: "AppImage",
204
+ });
205
+ ```
206
+
187
207
  ## API Reference
188
208
 
189
209
  Options
190
210
 
191
211
  | Name | Type | Default | Description |
192
212
  | --------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
193
- | mode | `"get" \| "run" \| "build"` | `"build"` | Choose between get, run or build mode |
213
+ | mode | `"get" \| "run" \| "build" \| "package"` | `"build"` | Choose between get, run, build or package mode |
194
214
  | version | `string \| "latest" \| "stable"` | `"latest"` | Runtime version |
195
215
  | flavor | `"normal" \| "sdk"` | `"normal"` | Runtime flavor |
196
216
  | platform | `"linux" \| "osx" \| "win"` | | Host platform |
@@ -209,6 +229,7 @@ Options
209
229
  | managedManifest | `boolean \| string \| object` | `false` | Managed manifest |
210
230
  | nodeAddon | `boolean` | `false` | Rebuild Node native addons |
211
231
  | zip | `boolean \| "zip" \| "tar" \| "tgz"` | `false` | If true, "zip", "tar" or "tgz" the `outDir` directory is compressed. |
232
+ | format | `"AppImage" \| "deb" \| "rpm" \| "msix" \| "nsis" \| "dmg"` | `"AppImage"` on Linux | Packaged output format, used in package mode. Only `"AppImage"` is implemented today. |
212
233
  | app | `LinuxRc \| WinRc \| OsxRc` | Additional options for each platform. (See below.) |
213
234
 
214
235
  ### `app` configuration object
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nw-builder",
3
- "version": "4.19.1",
3
+ "version": "4.20.0",
4
4
  "description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
5
5
  "keywords": [
6
6
  "NW.js",
@@ -21,7 +21,7 @@
21
21
  "contributors": [
22
22
  {
23
23
  "name": "nw-builder Contributors",
24
- "url": "https://github.com/nwutil/nw-builder/graphs/contributors"
24
+ "url": "https://github.com/nwutils/nw-builder/graphs/contributors"
25
25
  }
26
26
  ],
27
27
  "license": "MIT",
@@ -38,10 +38,10 @@
38
38
  "homepage": "https://github.com/nwutils/nw-builder",
39
39
  "repository": {
40
40
  "type": "git",
41
- "url": "https://github.com/nwutils/nw-builder.git"
41
+ "url": "git+https://github.com/nwutils/nw-builder.git",
42
+ "directory": "./packages/nw-builder"
42
43
  },
43
44
  "scripts": {
44
- "postinstall": "node ./src/postinstall.js",
45
45
  "lint": "eslint ./src ../../tests/specs/nw-builder",
46
46
  "lint:fix": "eslint --fix ./src ../../tests/specs/nw-builder",
47
47
  "type": "tsc",
@@ -61,6 +61,7 @@
61
61
  "dependencies": {
62
62
  "@nwutils/builder": "^0.1.0",
63
63
  "@nwutils/getter": "^0.2.5",
64
+ "@nwutils/packager": "^0.3.0",
64
65
  "@nwutils/runner": "^0.2.3",
65
66
  "commander": "^15.0.0",
66
67
  "glob": "^13.0.6"
package/src/cli.js CHANGED
@@ -8,7 +8,7 @@ import util from "./util.js";
8
8
 
9
9
  program
10
10
  .argument("<string>", "File path(s) to project")
11
- .option("--mode <string>", "get, run or build mode", "build")
11
+ .option("--mode <string>", "get, run, build or package mode", "build")
12
12
  .option("--version <string>", "NW.js version", "latest")
13
13
  .option("--flavor <string>", "NW.js build flavor", "normal")
14
14
  .option(
@@ -38,7 +38,6 @@ program
38
38
  .option(
39
39
  "--app <object>",
40
40
  "Platform specific app metadata. Refer to docs for more info",
41
- /** @type {any} */ ({}),
42
41
  )
43
42
  .option("--cache <boolean>", "Enable/disable caching", true)
44
43
  .option("--ffmpeg <boolean>", "Enable/disable community ffmpeg", false)
@@ -48,6 +47,7 @@ program
48
47
  .option("--zip <string>", "Enable/disable compression", false)
49
48
  .option("--managedManifest <string>", "Managed manifest mode", false)
50
49
  .option("--nodeAddon <boolean>", "Download NW.js Node headers", false)
50
+ .option("--format <string>", "Packaged output format, used in package mode")
51
51
  .allowUnknownOption(true)
52
52
  .allowExcessArguments(true);
53
53
 
package/src/index.d.ts CHANGED
@@ -8,8 +8,8 @@ export type SupportedPlatform = "linux" | "osx" | "win";
8
8
  export interface Options<P extends SupportedPlatform = SupportedPlatform> {
9
9
  /** String of space separated glob patterns which correspond to NW app code */
10
10
  srcDir?: "./" | string;
11
- /** Run or build application */
12
- mode?: "build" | "get" | "run";
11
+ /** Run, build or package application */
12
+ mode?: "build" | "get" | "run" | "package";
13
13
  /** NW runtime version */
14
14
  version?: "latest" | "stable" | string;
15
15
  /** NW runtime flavor */
@@ -42,6 +42,8 @@ export interface Options<P extends SupportedPlatform = SupportedPlatform> {
42
42
  logLevel?: "error" | "warn" | "info" | "debug";
43
43
  /** Managed manifest */
44
44
  managedManifest?: boolean | string | object;
45
+ /** Packaged output format, used in package mode. Defaults to `"AppImage"` on Linux. Only `"AppImage"` is implemented today - the others are reserved. */
46
+ format?: "AppImage" | "deb" | "rpm" | "msix" | "nsis" | "dmg";
45
47
  }
46
48
 
47
49
  /** Platform-specific application options */
@@ -183,6 +185,6 @@ export interface OsxAppOptions {
183
185
  */
184
186
  declare function nwbuild<P extends SupportedPlatform>(
185
187
  options: Options<P>,
186
- ): Promise<ChildProcess | null | undefined>;
188
+ ): Promise<ChildProcess | string | null | undefined>;
187
189
 
188
190
  export default nwbuild;
package/src/index.js CHANGED
@@ -5,13 +5,14 @@ import path from "node:path";
5
5
 
6
6
  import bld from "@nwutils/builder";
7
7
  import get from "@nwutils/getter";
8
+ import pkg from "@nwutils/packager";
8
9
  import run from "@nwutils/runner";
9
10
 
10
11
  import util from "./util.js";
11
12
 
12
13
  /**
13
14
  * @typedef {object} Options Configuration options
14
- * @property {"get" | "run" | "build"} [mode="build"] Choose between get, run or build mode
15
+ * @property {"get" | "run" | "build" | "package"} [mode="build"] Choose between get, run, build or package mode
15
16
  * @property {"latest" | "stable" | string} [version="latest"] Runtime version
16
17
  * @property {"normal" | "sdk"} [flavor="normal"] Runtime flavor
17
18
  * @property {"linux" | "osx" | "win"} [platform] Host platform
@@ -21,17 +22,18 @@ import util from "./util.js";
21
22
  * @property {"./cache" | string} [cacheDir="./cache"] Directory to cache NW binaries
22
23
  * @property {string | string[]} [srcDir="./"] File paths to application code
23
24
  * @property {"./out" | string} [outDir="./out"] Directory to store build artifacts
24
- * @property {object} [app] Refer to Linux/Windows Specific Options under Getting Started in the docs
25
+ * @property {import("./util.js").AppOptions} [app] Refer to Linux/Windows Specific Options under Getting Started in the docs
25
26
  * @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
26
27
  * @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
27
28
  * @property {boolean} [glob=true] If true file globbing is enabled when parsing srcDir.
28
29
  * @property {"error" | "warn" | "info" | "debug"} [logLevel="info"] Specify level of logging.
29
30
  * @property {boolean} [shaSum = true] If true, shasum is enabled. Otherwise, disabled.
30
31
  * @property {boolean | "zip" | "tar" | "tgz"} [zip=false] If true, "zip", "tar" or "tgz" the outDir directory is compressed.
31
- * @property {boolean | string | object} [managedManifest = false] Managed manifest mode
32
+ * @property {boolean | string | Record<string, unknown>} [managedManifest = false] Managed manifest mode
32
33
  * @property {boolean} [nativeAddon = false] Get Node native addons
33
34
  * @property {boolean} [cli=false] If true the CLI is used to parse options. This option is used internally.
34
35
  * @property {string[]} [argv = []] CLI arguments passed to the NW.js process in run mode
36
+ * @property {"AppImage" | "deb" | "rpm" | "msix" | "nsis" | "dmg"} [format] Packaged output format, used in package mode. Defaults to `"AppImage"` on Linux. Only `"AppImage"` is implemented today - the others are reserved.
35
37
  */
36
38
 
37
39
  /**
@@ -39,12 +41,12 @@ import util from "./util.js";
39
41
  * @async
40
42
  * @function
41
43
  * @param {Options} options Options
42
- * @returns {Promise<child_process.ChildProcess | null | undefined>} - Returns NW.js process if run mode, otherwise returns `undefined`.
44
+ * @returns {Promise<child_process.ChildProcess | string | null | undefined>} - Returns the NW.js process in run mode, the path to the packaged artifact in package mode, otherwise returns `undefined`.
43
45
  */
44
46
  async function nwbuild(options) {
45
47
  let built;
46
48
  let releaseInfo;
47
- /** @type {{path: string, json: any}} */
49
+ /** @type {{path: string, json: import("./util.js").PackageManifest | undefined}} */
48
50
  let manifest = {
49
51
  path: "",
50
52
  json: undefined,
@@ -52,7 +54,9 @@ async function nwbuild(options) {
52
54
 
53
55
  try {
54
56
  /* Parse options */
55
- options = await util.parse(options, manifest);
57
+ options = /** @type {Options} */ (
58
+ await util.parse(options, manifest.json ?? {})
59
+ );
56
60
  util.log("debug", "info", "Parse initial options");
57
61
 
58
62
  util.log("debug", "info", "Get node manifest...");
@@ -69,8 +73,9 @@ async function nwbuild(options) {
69
73
  /** @type {"debug" | "error" | "info" | "warn"} */ (options.logLevel),
70
74
  "Parse final options using node manifest",
71
75
  );
72
- /** @type {Required<Options>} */
73
- const resolved = await util.parse(options, manifest.json);
76
+ const resolved = /** @type {Required<Options>} */ (
77
+ await util.parse(options, manifest.json ?? {})
78
+ );
74
79
  util.log(
75
80
  "debug",
76
81
  resolved.logLevel,
@@ -113,7 +118,9 @@ async function nwbuild(options) {
113
118
  );
114
119
 
115
120
  /* Remove leading "v" from version string */
116
- resolved.version = releaseInfo.version.slice(1);
121
+ resolved.version = /** @type {import("./util.js").ReleaseInfo} */ (
122
+ releaseInfo
123
+ ).version.slice(1);
117
124
 
118
125
  util.log(
119
126
  "info",
@@ -158,7 +165,7 @@ async function nwbuild(options) {
158
165
  argv: resolved.argv,
159
166
  });
160
167
  return nwProcess;
161
- } else if (resolved.mode === "build") {
168
+ } else if (resolved.mode === "build" || resolved.mode === "package") {
162
169
  util.log(
163
170
  "info",
164
171
  resolved.logLevel,
@@ -173,7 +180,9 @@ async function nwbuild(options) {
173
180
  srcDir: /** @type {string} */ (resolved.srcDir),
174
181
  cacheDir: resolved.cacheDir,
175
182
  outDir: resolved.outDir,
176
- app: /** @type {any} */ (resolved.app),
183
+ app: /** @type {import("@nwutils/builder").LinuxRc | import("@nwutils/builder").WinRc | import("@nwutils/builder").OsxRc} */ (
184
+ resolved.app
185
+ ),
177
186
  glob: resolved.glob,
178
187
  managedManifest: resolved.managedManifest,
179
188
  zip: resolved.zip,
@@ -184,6 +193,29 @@ async function nwbuild(options) {
184
193
  resolved.logLevel,
185
194
  `Appliction is available at ${path.resolve(resolved.outDir)}`,
186
195
  );
196
+
197
+ if (resolved.mode === "package") {
198
+ util.log(
199
+ "info",
200
+ resolved.logLevel,
201
+ `Packaging NW.js application as ${resolved.format}...`,
202
+ );
203
+ const packagePath = await pkg({
204
+ format: resolved.format,
205
+ appDir: resolved.outDir,
206
+ appName: resolved.app.name,
207
+ icon: resolved.app.icon,
208
+ arch: resolved.arch,
209
+ cacheDir: resolved.cacheDir,
210
+ cache: resolved.cache,
211
+ });
212
+ util.log(
213
+ "info",
214
+ resolved.logLevel,
215
+ `Package is available at ${packagePath}`,
216
+ );
217
+ return packagePath;
218
+ }
187
219
  }
188
220
  } catch (error) {
189
221
  console.error(error);
package/src/util.js CHANGED
@@ -7,6 +7,118 @@ import url from "node:url";
7
7
 
8
8
  import * as GlobModule from "glob";
9
9
 
10
+ /**
11
+ * Linux/Windows/OSX specific application configuration. Every property maps
12
+ * to a `LinuxRc`/`WinRc`/`OsxRc` field from `@nwutils/builder`, kept optional
13
+ * here since which ones are required depends on `options.platform` - that is
14
+ * checked at runtime by `validate()`.
15
+ * @typedef {object} AppOptions
16
+ * @property {string} [name] Name of the application
17
+ * @property {string} [icon] Path to icon file
18
+ * @property {string} [genericName] Generic name of the application
19
+ * @property {boolean} [noDisplay] If true the application is not displayed
20
+ * @property {string} [comment] Tooltip for the entry
21
+ * @property {string | boolean} [hidden] Whether the entry is hidden
22
+ * @property {string[]} [onlyShowIn] Desktop environments that should display this entry
23
+ * @property {string[]} [notShowIn] Desktop environments that should not display this entry
24
+ * @property {boolean} [dBusActivatable] If true D-Bus activation is supported
25
+ * @property {string} [tryExec] Executable used to determine if the program is installed
26
+ * @property {string} [exec] Program to execute, possibly with arguments
27
+ * @property {string} [path] Working directory to run the program in
28
+ * @property {boolean} [terminal] Whether the program runs in a terminal window
29
+ * @property {string[]} [actions] Identifiers for application actions
30
+ * @property {string[]} [mimeType] MIME type(s) supported by this application
31
+ * @property {string[]} [categories] Menu categories the entry should be shown in
32
+ * @property {string[]} [implements] Interfaces this application implements
33
+ * @property {string[]} [keywords] Additional strings used to describe this entry
34
+ * @property {boolean} [startupNotify] Whether the application supports startup notification
35
+ * @property {string} [startupWMClass] WM class or WM name hint the application maps
36
+ * @property {boolean} [prefersNonDefaultGPU] If true prefers running on a discrete GPU
37
+ * @property {string} [singleMainWindow] If true the application has a single main window
38
+ * @property {string} [version] Version of the application
39
+ * @property {string} [comments] Additional diagnostic information
40
+ * @property {string} [company] Company that produced the file
41
+ * @property {string} [fileDescription] File description presented to users
42
+ * @property {string} [fileVersion] Version number of the file
43
+ * @property {string} [internalName] Internal name of the file
44
+ * @property {string} [legalCopyright] Copyright notices that apply to the file
45
+ * @property {string} [legalTrademark] Trademarks that apply to the file
46
+ * @property {string} [originalFilename] Original name of the file
47
+ * @property {string} [privateBuild] Information about a private build
48
+ * @property {string} [productName] Name of the product the file is distributed with
49
+ * @property {string} [productVersion] Version of the product the file is distributed with
50
+ * @property {string} [specialBuild] How this build differs from the standard version
51
+ * @property {number} [languageCode] Language identifier (LCID) of the file
52
+ * @property {string} [LSApplicationCategoryType] App Store category
53
+ * @property {string} [CFBundleIdentifier] Unique bundle identifier, usually reverse DNS
54
+ * @property {string} [CFBundleName] User-visible short name for the bundle
55
+ * @property {string} [CFBundleDisplayName] User-visible name for the bundle
56
+ * @property {string} [CFBundleSpokenName] Replacement app name for text-to-speech
57
+ * @property {string} [CFBundleShortVersionString] Release or version number of the bundle
58
+ * @property {string} [CFBundleVersion] Build version that identifies a bundle iteration
59
+ * @property {string} [NSHumanReadableCopyright] Human-readable copyright notice
60
+ * @property {string} [NSLocalNetworkUsageDescription] Why the app needs local network access
61
+ * @property {boolean} [LSFileQuarantineEnabled] Whether files this app creates are quarantined
62
+ */
63
+
64
+ /**
65
+ * Minimal shape of the `package.json` fields read while resolving options.
66
+ * @typedef {object} PackageManifest
67
+ * @property {string} [name] Package name
68
+ * @property {string} [version] Package version
69
+ * @property {string} [author] Package author
70
+ * @property {string} [description] Package description
71
+ * @property {{icon?: string}} [window] NW.js manifest `window` configuration
72
+ * @property {object} [nwbuild] `nwbuild` options embedded in the manifest
73
+ */
74
+
75
+ /**
76
+ * Version specific NW.js release metadata, as found in the `versions` array
77
+ * of the manifest at `manifestUrl`.
78
+ * @typedef {object} ReleaseInfo
79
+ * @property {string} version NW.js version, eg. `"v0.115.0"`
80
+ * @property {string[]} flavors Flavors this release is published for
81
+ * @property {string[]} files Supported `<platform>-<arch>` combinations
82
+ */
83
+
84
+ /**
85
+ * The versions manifest NW.js releases are published to.
86
+ * @typedef {object} VersionsManifest
87
+ * @property {string} latest Latest published version
88
+ * @property {string} stable Latest stable version
89
+ * @property {string} lts Latest LTS version
90
+ * @property {ReleaseInfo[]} versions Every published release
91
+ */
92
+
93
+ /**
94
+ * `nwbuild` options, partially or fully resolved. Every field is optional
95
+ * and loosely typed as supplied by the caller or CLI (eg. `cache` may arrive
96
+ * as the string `"true"`) - `parse()` normalizes them in place.
97
+ * @typedef {object} Options
98
+ * @property {"get" | "run" | "build" | "package"} [mode] Choose between get, run, build or package mode
99
+ * @property {string} [version] Runtime version
100
+ * @property {"normal" | "sdk"} [flavor] Runtime flavor
101
+ * @property {"linux" | "osx" | "win"} [platform] Host platform
102
+ * @property {"ia32" | "x64" | "arm64"} [arch] Host architecture
103
+ * @property {string} [downloadUrl] Download server
104
+ * @property {string} [manifestUrl] Versions manifest URI
105
+ * @property {string} [cacheDir] Directory to cache NW binaries
106
+ * @property {boolean | string} [cache] If true the existing cache is used
107
+ * @property {boolean | string} [ffmpeg] If true the community ffmpeg is used
108
+ * @property {"error" | "warn" | "info" | "debug"} [logLevel] Specify level of logging
109
+ * @property {boolean | string} [shaSum] If true, shasum is enabled
110
+ * @property {boolean | string} [nativeAddon] Get Node native addons
111
+ * @property {"AppImage" | "deb" | "rpm" | "msix" | "nsis" | "dmg"} [format] Packaged output format, used in package mode
112
+ * @property {string[]} [argv] CLI arguments passed to the NW.js process in run mode
113
+ * @property {boolean | string} [glob] If true file globbing is enabled when parsing srcDir
114
+ * @property {string | string[]} [srcDir] File paths to application code
115
+ * @property {string} [outDir] Directory to store build artifacts
116
+ * @property {boolean | string} [zip] If truthy, the outDir directory is compressed
117
+ * @property {boolean | string | Record<string, unknown>} [managedManifest] Managed manifest mode
118
+ * @property {AppOptions} [app] Platform specific app metadata
119
+ * @property {boolean} [cli] If true the CLI is used to parse options
120
+ */
121
+
10
122
  /**
11
123
  * Get manifest (array of NW release metadata) from URL.
12
124
  * @param {string} manifestUrl Versions manifest URI, https or file path
@@ -49,7 +161,7 @@ function getManifest(manifestUrl) {
49
161
  * @param {string} arch NW architecture
50
162
  * @param {string} cacheDir Directory to store NW binaries
51
163
  * @param {string} manifestUrl Versions manifest URI, https or file path
52
- * @returns {Promise<any>} Version specific release info
164
+ * @returns {Promise<ReleaseInfo | undefined>} Version specific release info
53
165
  */
54
166
  async function getReleaseInfo(version, platform, arch, cacheDir, manifestUrl) {
55
167
  let releaseData = undefined;
@@ -66,7 +178,7 @@ async function getReleaseInfo(version, platform, arch, cacheDir, manifestUrl) {
66
178
  await fs.promises.writeFile(manifestPath, data);
67
179
  }
68
180
 
69
- /** @type {any} */
181
+ /** @type {VersionsManifest} */
70
182
  const manifest = JSON.parse(
71
183
  await fs.promises.readFile(manifestPath, "utf8"),
72
184
  );
@@ -76,7 +188,7 @@ async function getReleaseInfo(version, platform, arch, cacheDir, manifestUrl) {
76
188
  }
77
189
 
78
190
  releaseData = manifest.versions.find(
79
- (/** @type {any} */ release) => release.version === `v${version}`,
191
+ (release) => release.version === `v${version}`,
80
192
  );
81
193
  } catch {
82
194
  console.error(
@@ -86,12 +198,14 @@ async function getReleaseInfo(version, platform, arch, cacheDir, manifestUrl) {
86
198
  return releaseData;
87
199
  }
88
200
 
201
+ /** @type {Record<"darwin" | "linux" | "win32", "linux" | "osx" | "win">} */
89
202
  const PLATFORM_KV = {
90
203
  darwin: "osx",
91
204
  linux: "linux",
92
205
  win32: "win",
93
206
  };
94
207
 
208
+ /** @type {Record<"x64" | "ia32" | "arm64", "x64" | "ia32" | "arm64">} */
95
209
  const ARCH_KV = {
96
210
  x64: "x64",
97
211
  ia32: "ia32",
@@ -143,10 +257,10 @@ async function globFiles({ srcDir, glob }) {
143
257
  * @param {object} options - node manifest options
144
258
  * @param {string | string []} options.srcDir - src dir
145
259
  * @param {boolean} options.glob - glob flag
146
- * @returns {Promise.<{path: string, json: object}>} - Node manifest
260
+ * @returns {Promise<{path: string, json: PackageManifest | undefined}>} - Node manifest
147
261
  */
148
262
  async function getNodeManifest({ srcDir, glob }) {
149
- /** @type {{path: string, json: any}} */
263
+ /** @type {{path: string, json: PackageManifest | undefined}} */
150
264
  let manifest = {
151
265
  path: "",
152
266
  json: undefined,
@@ -184,24 +298,31 @@ async function getNodeManifest({ srcDir, glob }) {
184
298
  /**
185
299
  * Function to convert `'true'` and `'false'` into `true` and `false`.
186
300
  * `commander` does not do the conversion automatically.
187
- * @param {string} option - a boolean type option
188
- * @returns {true | false | string} `true`, `false` or file path
301
+ * @template {string | boolean | Record<string, unknown> | undefined} T
302
+ * @param {T} option - a boolean type option
303
+ * @returns {T extends "true" ? true : T extends "false" ? false : T} `true`, `false` or file path
189
304
  */
190
305
  function str2Bool(option) {
191
306
  if (option === "true") {
192
- return true;
307
+ return /** @type {T extends "true" ? true : T extends "false" ? false : T} */ (
308
+ true
309
+ );
193
310
  } else if (option === "false") {
194
- return false;
311
+ return /** @type {T extends "true" ? true : T extends "false" ? false : T} */ (
312
+ false
313
+ );
195
314
  } else {
196
- return option;
315
+ return /** @type {T extends "true" ? true : T extends "false" ? false : T} */ (
316
+ option
317
+ );
197
318
  }
198
319
  }
199
320
 
200
321
  /**
201
322
  * Parse options.
202
- * @param {any} options Options
203
- * @param {any} pkg Package.json as JSON
204
- * @returns {Promise<any>} Options
323
+ * @param {Options | undefined} options Options
324
+ * @param {PackageManifest} pkg Package.json as JSON
325
+ * @returns {Promise<Options>} Options
205
326
  */
206
327
  export const parse = async (options, pkg) => {
207
328
  options = options ?? {};
@@ -228,6 +349,11 @@ export const parse = async (options, pkg) => {
228
349
  return { ...options };
229
350
  }
230
351
 
352
+ if (options.mode === "package") {
353
+ options.format =
354
+ options.format ?? (options.platform === "linux" ? "AppImage" : undefined);
355
+ }
356
+
231
357
  options.argv = options.argv ?? [];
232
358
  options.glob = str2Bool(options.glob) ?? true;
233
359
  options.srcDir = options.srcDir ?? (options.glob ? "./*" : ".");
@@ -327,8 +453,8 @@ export const parse = async (options, pkg) => {
327
453
 
328
454
  /**
329
455
  * Validate options.
330
- * @param {any} options Options
331
- * @param {any} releaseInfo Version specific NW release info
456
+ * @param {Options} options Options
457
+ * @param {ReleaseInfo | undefined} releaseInfo Version specific NW release info
332
458
  * @returns {Promise<undefined>} Return undefined if options are valid
333
459
  * @throws {Error} Throw error if options are invalid
334
460
  */
@@ -336,10 +462,11 @@ export const validate = async (options, releaseInfo) => {
336
462
  if (
337
463
  options.mode !== "get" &&
338
464
  options.mode !== "run" &&
339
- options.mode !== "build"
465
+ options.mode !== "build" &&
466
+ options.mode !== "package"
340
467
  ) {
341
468
  throw new Error(
342
- `Unknown mode ${options.mode}. Expected "get", "run" or "build".`,
469
+ `Unknown mode ${options.mode}. Expected "get", "run", "build" or "package".`,
343
470
  );
344
471
  }
345
472
  if (typeof releaseInfo === "undefined") {
@@ -347,6 +474,8 @@ export const validate = async (options, releaseInfo) => {
347
474
  "Either the specific version info does not exist or the version manifest itself does not exist. In case of the latter, please check your internet connection and try again later.",
348
475
  );
349
476
  }
477
+ /* By the time validate() runs, parse() has already defaulted options.flavor. */
478
+ options.flavor = options.flavor ?? "normal";
350
479
  if (!releaseInfo.flavors.includes(options.flavor)) {
351
480
  throw new Error(
352
481
  `${options.flavor} flavor is not supported by this download server.`,
@@ -484,6 +613,30 @@ export const validate = async (options, releaseInfo) => {
484
613
  );
485
614
  }
486
615
 
616
+ if (options.mode === "package") {
617
+ if (
618
+ options.format !== "AppImage" &&
619
+ options.format !== "deb" &&
620
+ options.format !== "rpm" &&
621
+ options.format !== "msix" &&
622
+ options.format !== "nsis" &&
623
+ options.format !== "dmg"
624
+ ) {
625
+ throw new Error(
626
+ 'Expected options.format to be one of "AppImage", "deb", "rpm", "msix", "nsis" or "dmg". Got ' +
627
+ JSON.stringify(options.format),
628
+ );
629
+ }
630
+ if (options.format === "AppImage" && options.platform !== "linux") {
631
+ throw new Error(
632
+ `options.format "AppImage" requires options.platform to be "linux". Got ${JSON.stringify(options.platform)}.`,
633
+ );
634
+ }
635
+ }
636
+
637
+ /* By the time validate() runs, parse() has already defaulted options.app to {}. */
638
+ options.app = options.app ?? {};
639
+
487
640
  if (options.platform === "linux") {
488
641
  if (options.app.name && typeof options.app.name !== "string") {
489
642
  throw new Error(
@@ -852,7 +1005,7 @@ export const validate = async (options, releaseInfo) => {
852
1005
  * @async
853
1006
  * @function
854
1007
  * @param {"chromedriver"} type - NW specific file or directory
855
- * @param {any} options - nwbuild options
1008
+ * @param {{cacheDir: string, flavor: string, version: string, platform: string, arch: string}} options - nwbuild options
856
1009
  * @returns {Promise<string>} - Path to chromedriver
857
1010
  * @throws {Error}
858
1011
  */
@@ -1,19 +0,0 @@
1
- import path from "node:path";
2
- import url from "node:url";
3
-
4
- const __dirname = path.dirname(url.fileURLToPath(import.meta.url));
5
-
6
- const baseVoltaPath = path.resolve(
7
- path.join(
8
- __dirname,
9
- "..",
10
- "node_modules",
11
- "base-volta-off-of-nwjs",
12
- "index.js",
13
- ),
14
- );
15
-
16
- /* Execute the script in development mode only since it is used during testing */
17
- import(baseVoltaPath)
18
- .then(() => console.log("Node version is updated"))
19
- .catch((error) => console.log(error));