nw-builder 4.0.11 → 4.1.0-beta.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
@@ -11,6 +11,7 @@ Build [NW.js](https://github.com/nwjs/nw.js) applications for Mac, Windows and L
11
11
  - [Usage](https://github.com/nwutils/nw-builder#usage)
12
12
  - [Limitations](https://github.com/nwutils/nw-builder#limitations)
13
13
  - [API Reference](https://nwutils.io/nw-builder/global#nwbuild)
14
+ - [Migration Guide](https://github.com/nwutils/nw-builder#migration)
14
15
  - [Contributing](https://github.com/nwutils/nw-builder#contributing)
15
16
  - [License](https://github.com/nwutils/nw-builder#license)
16
17
 
@@ -32,7 +33,7 @@ Module usage
32
33
  import nwbuild from "nw-builder";
33
34
 
34
35
  nwbuild({
35
- srcDir: "./nwapp/**/*",
36
+ srcDir: "./nwapp/*",
36
37
  mode: "run",
37
38
  version: "latest",
38
39
  flavor: "sdk",
@@ -42,7 +43,7 @@ nwbuild({
42
43
  CLI usage
43
44
 
44
45
  ```shell
45
- nwbuild ./nwapp/**/* --mode=run --version=latest --flavor=sdk
46
+ nwbuild ./nwapp/* --mode=run --version=latest --flavor=sdk
46
47
  ```
47
48
 
48
49
  package.json usage
@@ -54,7 +55,7 @@ package.json usage
54
55
  "name": "nwdemo",
55
56
  "main": "./index.html",
56
57
  "nwbuild": {
57
- "srcDir": "./nwapp/**/*",
58
+ "srcDir": "./nwapp/*",
58
59
  "mode": "run",
59
60
  "version": "latest",
60
61
  "flavor": "sdk"
@@ -70,7 +71,7 @@ Module usage
70
71
  import nwbuild from "nw-builder";
71
72
 
72
73
  nwbuild({
73
- srcDir: "./nwapp/**/*",
74
+ srcDir: "./nwapp/*",
74
75
  mode: "build",
75
76
  version: "latest",
76
77
  flavor: "normal",
@@ -83,7 +84,7 @@ nwbuild({
83
84
  CLI usage
84
85
 
85
86
  ```shell
86
- nwbuild ./nwapp/**/* --mode=build --version=latest --flavor=normal --platform=linux --arch=x64 --outDir=./out
87
+ nwbuild ./nwapp/* --mode=build --version=latest --flavor=normal --platform=linux --arch=x64 --outDir=./out
87
88
  ```
88
89
 
89
90
  package.json usage
@@ -95,7 +96,7 @@ package.json usage
95
96
  "name": "nwdemo",
96
97
  "main": "./index.html",
97
98
  "nwbuild": {
98
- "srcDir": "./nwapp/**/*",
99
+ "srcDir": "./nwapp/*",
99
100
  "mode": "build",
100
101
  "version": "latest",
101
102
  "flavor": "normal",
@@ -112,7 +113,9 @@ For more options, check out the [API reference](https://nwutils.io/nw-builder/gl
112
113
 
113
114
  - #716 File permissions are incorrectly set for Linux or MacOS apps built on Windows platform.
114
115
 
115
- ## Migration to v4
116
+ ## Migration
117
+
118
+ Migrate from v3 to v4
116
119
 
117
120
  ### Update `nw-builder`
118
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nw-builder",
3
- "version": "4.0.11",
3
+ "version": "4.1.0-beta.0",
4
4
  "description": "Build NW.js desktop applications for MacOS, Windows and Linux.",
5
5
  "keywords": [
6
6
  "NW.js",
@@ -8,11 +8,7 @@
8
8
  "Desktop",
9
9
  "Application"
10
10
  ],
11
- "author": {
12
- "name": "Steffen Müller",
13
- "email": "steffen@mllrsohn.com",
14
- "url": "https://github.com/steffenmllr"
15
- },
11
+ "author": "nw-builder Authors",
16
12
  "license": "MIT",
17
13
  "exports": {
18
14
  "default": "./src/nwbuild.js"
@@ -28,37 +24,34 @@
28
24
  "url": "https://github.com/nwutils/nw-builder.git"
29
25
  },
30
26
  "scripts": {
31
- "format": "prettier --write \"./**/*.{css,html,js,json,md}\"",
32
- "lint": "eslint ./src",
33
- "docs": "jsdoc ./src/nwbuild.js -d docs",
27
+ "fmt": "prettier --write \"./**/*.{css,html,js,json,md,yml}\"",
28
+ "lnt": "eslint ./src",
29
+ "doc": "jsdoc ./src/nwbuild.js -d docs",
30
+ "e2e": "node --test e2e/index.js",
34
31
  "test:unit": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
35
- "test:e2e": "cd ./test/e2e && node bld.js && node run.js",
36
- "demo:cli": "cd ./test/e2e && nwbuild ./nwapp/* ./nwapp/**/* --mode=build --version=latest --flavor=normal --platform=linux --arch=x64 --outDir=./build/cli",
37
- "demo:nix": "cd test/e2e && node nix.js",
38
- "demo:osx": "cd ./test/e2e && node osx.js",
39
- "demo:win": "cd ./test/e2e && node win.js"
32
+ "demo:esm": "cd e2e && node demo.js",
33
+ "demo:cjs": "cd e2e && node demo.cjs",
34
+ "demo:cli": "cd ./test && nwbuild ./nwapp/* --mode=build --version=latest --flavor=normal --platform=linux --arch=x64 --outDir=./build/cli"
40
35
  },
41
36
  "devDependencies": {
42
- "eslint": "^8.25.0",
37
+ "eslint": "^8.34.0",
43
38
  "eslint-config-tjw-jsdoc": "^1.0.3",
44
- "jest": "^29.2.0",
45
- "jest-environment-jsdom": "^29.2.0",
46
- "jsdoc": "^4.0.0",
47
- "jsdom": "^21.0.0",
48
- "prettier": "^2.7.1"
39
+ "jest": "^29.4.3",
40
+ "jest-environment-jsdom": "^29.4.3",
41
+ "jsdoc": "^4.0.2",
42
+ "jsdom": "^21.1.0",
43
+ "prettier": "^2.8.4",
44
+ "selenium-webdriver": "^4.8.0"
49
45
  },
50
46
  "dependencies": {
51
47
  "archiver": "^5.3.1",
52
- "cli-progress": "^3.11.2",
53
- "extract-zip": "^2.0.1",
54
- "glob-promise": "^6.0.0",
48
+ "cli-progress": "^3.12.0",
49
+ "decompress": "^4.2.1",
50
+ "glob-promise": "^6.0.2",
55
51
  "plist": "^3.0.6",
56
- "progress": "^2.0.3",
57
52
  "rcedit": "^3.0.1",
58
- "tar": "^6.1.11",
59
- "update-notifier": "^6.0.2",
60
53
  "winston": "^3.8.2",
61
- "yargs": "^17.5.1"
54
+ "yargs": "^17.7.1"
62
55
  },
63
56
  "bin": {
64
57
  "nwbuild": "./src/cli.js"
@@ -81,7 +74,7 @@
81
74
  },
82
75
  "eslintConfig": {
83
76
  "parserOptions": {
84
- "ecmaVersion": 2021,
77
+ "ecmaVersion": 2023,
85
78
  "sourceType": "module"
86
79
  },
87
80
  "env": {
@@ -95,7 +88,9 @@
95
88
  ],
96
89
  "rules": {
97
90
  "jsdoc/require-file-overview": "off",
98
- "jsdoc/match-description": "off"
91
+ "jsdoc/require-returns-description": "off",
92
+ "jsdoc/match-description": "off",
93
+ "jsdoc/valid-types": "off"
99
94
  }
100
95
  },
101
96
  "jest": {
@@ -3,13 +3,20 @@ import archiver from "archiver";
3
3
 
4
4
  import { log } from "../log.js";
5
5
 
6
+ /**
7
+ * Compress a out directory
8
+ *
9
+ * @param {string} outDir - Output directory
10
+ * @param {string} type - Compression type
11
+ * @return {Promise<undefined>}
12
+ */
6
13
  const compress = (outDir, type = "zip") => {
7
14
  const output = fs.createWriteStream(`${outDir}.${type}`);
8
15
  const archive = archiver("zip");
9
16
 
10
17
  return new Promise((res, rej) => {
11
18
  output.on("close", () => {
12
- res(0);
19
+ res();
13
20
  });
14
21
 
15
22
  archive.on("warning", (err) => {
@@ -7,9 +7,9 @@ import { log } from "../log.js";
7
7
  * Generates a Desktop Entry file for Linux
8
8
  * https://specifications.freedesktop.org/desktop-entry-spec/latest/ar01s06.html
9
9
  *
10
- * @param {object} app Multi platform configuration options
11
- * @param {string} outDir Directory which stores build artifacts
12
- * @return {undefined}
10
+ * @param {object} app Multi platform configuration options
11
+ * @param {string} outDir Directory which stores build artifacts
12
+ * @return {Promise<void>}
13
13
  */
14
14
  export const setLinuxConfig = async (app, outDir) => {
15
15
  if (platform === "win32") {
@@ -1,4 +1,4 @@
1
- import { sep } from "node:path";
1
+ import { resolve } from "node:path";
2
2
  import { cp, rm } from "node:fs/promises";
3
3
 
4
4
  import { log } from "../log.js";
@@ -34,13 +34,17 @@ const packager = async (
34
34
  log.debug(`Copy ${nwDir} files to ${outDir} directory`);
35
35
  await cp(nwDir, outDir, { recursive: true });
36
36
 
37
+ log.debug(`Copy ${nwDir} files to ${outDir} directory`);
37
38
  for (let file of files) {
38
39
  log.debug(`Copy ${file} file to ${outDir} directory`);
39
40
  await cp(
40
41
  file,
41
- `${outDir}/${
42
- platform !== "osx" ? "package.nw" : "nwjs.app/Contents/Resources/app.nw"
43
- }/${file.split(sep).splice(2).join(sep)}`,
42
+ resolve(
43
+ outDir,
44
+ platform !== "osx"
45
+ ? "package.nw"
46
+ : "nwjs.app/Contents/Resources/app.nw",
47
+ ),
44
48
  {
45
49
  recursive: true,
46
50
  },
@@ -50,13 +54,13 @@ const packager = async (
50
54
  log.debug(`Starting platform specific config steps for ${platform}`);
51
55
  switch (platform) {
52
56
  case "linux":
53
- setLinuxConfig(app, outDir);
57
+ await setLinuxConfig(app, outDir);
54
58
  break;
55
59
  case "win":
56
- setWinConfig(app, outDir);
60
+ await setWinConfig(app, outDir);
57
61
  break;
58
62
  case "osx":
59
- setOsxConfig(app, outDir, releaseInfo);
63
+ await setOsxConfig(app, outDir, releaseInfo);
60
64
  break;
61
65
  default:
62
66
  break;
@@ -1,34 +1,40 @@
1
- import path from "node:path";
1
+ import { resolve } from "node:path";
2
2
 
3
- import extract from "extract-zip";
4
- import tar from "tar";
3
+ import Decompress from "decompress";
5
4
 
6
- const decompress = (platform, outDir) => {
7
- return new Promise((resolve, reject) => {
8
- if (platform === "linux") {
9
- tar
10
- .x({
11
- file: `${outDir}/nw.tar.gz`,
12
- C: `${outDir}`,
13
- })
14
- .then(() => {
15
- resolve();
16
- })
17
- .catch((error) => {
18
- reject(error);
19
- });
20
- } else {
21
- extract(path.resolve(`${outDir}/nw.zip`), {
22
- dir: path.resolve(`${outDir}`),
23
- })
24
- .then(() => {
25
- resolve();
26
- })
27
- .catch((error) => {
28
- reject(error);
29
- });
5
+ import { log } from "../log.js";
6
+
7
+ /**
8
+ * Decompress NW.js binary
9
+ *
10
+ * @param {string} platform Platform
11
+ * @param {string} cacheDir Output directory
12
+ * @param {string} downloadUrl Download url
13
+ * @return {Promise<void>}
14
+ */
15
+ const decompress = async (platform, cacheDir, downloadUrl) => {
16
+ try {
17
+ if (downloadUrl === "https://dl.nwjs.io") {
18
+ if (platform === "linux") {
19
+ await Decompress(resolve(cacheDir, "nw.tar.gz"), cacheDir);
20
+ } else {
21
+ await Decompress(resolve(cacheDir, "nw.zip"), cacheDir);
22
+ }
23
+ } else if (
24
+ downloadUrl ===
25
+ "https://github.com/corwin-of-amber/nw.js/releases/download"
26
+ ) {
27
+ await Decompress(resolve(cacheDir, "nw.zip"), cacheDir);
28
+ } else if (
29
+ downloadUrl ===
30
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
31
+ ) {
32
+ await Decompress(resolve(cacheDir, "ffmpeg.zip"), cacheDir);
30
33
  }
31
- });
34
+ } catch (error) {
35
+ log.error(error);
36
+ throw error;
37
+ }
32
38
  };
33
39
 
34
40
  export { decompress };
@@ -1,53 +1,95 @@
1
1
  import fs from "node:fs";
2
- import https from "node:https";
2
+ import { resolve } from "node:path";
3
+ import https from "https";
3
4
 
4
5
  import progress from "cli-progress";
5
6
 
6
7
  const bar = new progress.SingleBar({}, progress.Presets.rect);
7
8
 
9
+ /**
10
+ * Download NW.js binary
11
+ *
12
+ * @param {string} version Version
13
+ * @param {string} flavor Flavor
14
+ * @param {string} platform Platform
15
+ * @param {string} architecture Architecture
16
+ * @param {string} downloadUrl Download url
17
+ * @param {string} cacheDir Output directory
18
+ * @return {Promise<void>}
19
+ */
8
20
  const download = (
9
21
  version,
10
22
  flavor,
11
23
  platform,
12
24
  architecture,
13
25
  downloadUrl,
14
- outDir,
26
+ cacheDir,
15
27
  ) => {
16
- return new Promise((resolve, reject) => {
17
- if (downloadUrl !== "https://dl.nwjs.io") {
18
- reject(new Error("Invalid download url. Please try again."));
28
+ let url;
29
+ let out;
30
+ return new Promise((res, rej) => {
31
+ if (downloadUrl === "https://dl.nwjs.io") {
32
+ url = `${downloadUrl}/v${version}/nwjs${
33
+ flavor === "sdk" ? "-sdk" : ""
34
+ }-v${version}-${platform}-${architecture}.${
35
+ platform === "linux" ? "tar.gz" : "zip"
36
+ }`;
37
+ out = resolve(cacheDir, `nw.${platform === "linux" ? "tar.gz" : "zip"}`);
38
+ } else if (
39
+ downloadUrl ===
40
+ "https://github.com/corwin-of-amber/nw.js/releases/download"
41
+ ) {
42
+ url = `${downloadUrl}/nw-v${version}/nwjs-${
43
+ flavor === "sdk" ? "sdk-" : ""
44
+ }v${version}-${platform}-${architecture}.zip`;
45
+ out = resolve(cacheDir, `nw.zip`);
46
+ } else if (
47
+ downloadUrl ===
48
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
49
+ ) {
50
+ url = `${downloadUrl}/${version}/${version}-${platform}-${architecture}.zip`;
51
+ out = resolve(cacheDir, `ffmpeg.zip`);
52
+ } else {
53
+ rej(new Error("Invalid download url. Please try again."));
19
54
  }
20
55
 
21
- let url = `${downloadUrl}/v${version}/nwjs${
22
- flavor === "sdk" ? "-sdk" : ""
23
- }-v${version}-${platform}-${architecture}.${
24
- platform === "linux" ? "tar.gz" : "zip"
25
- }`;
56
+ https.get(url, (response) => {
57
+ // For GitHub releases, we need to follow the redirect
58
+ if (
59
+ downloadUrl ===
60
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download" ||
61
+ downloadUrl ===
62
+ "https://github.com/corwin-of-amber/nw.js/releases/download"
63
+ ) {
64
+ url = response.headers.location;
65
+ }
26
66
 
27
- https.get(url, (res) => {
28
- let chunks = 0;
29
- bar.start(Number(res.headers["content-length"]), 0);
67
+ https.get(url, (response) => {
68
+ let chunks = 0;
69
+ bar.start(Number(response.headers["content-length"]), 0);
70
+ response.on("data", (chunk) => {
71
+ chunks += chunk.length;
72
+ bar.increment();
73
+ bar.update(chunks);
74
+ });
30
75
 
31
- res.on("data", (chunk) => {
32
- chunks += chunk.length;
33
- bar.increment();
34
- bar.update(chunks);
35
- });
76
+ response.on("error", (error) => {
77
+ rej(error);
78
+ });
36
79
 
37
- res.on("error", (error) => {
38
- reject(error);
39
- });
80
+ response.on("end", () => {
81
+ bar.stop();
82
+ res();
83
+ });
40
84
 
41
- res.on("end", () => {
42
- bar.stop();
43
- resolve();
85
+ fs.mkdirSync(cacheDir, { recursive: true });
86
+ const stream = fs.createWriteStream(out);
87
+ response.pipe(stream);
44
88
  });
45
89
 
46
- fs.mkdirSync(outDir, { recursive: true });
47
- const stream = fs.createWriteStream(
48
- `${outDir}/nw.${platform === "linux" ? "tar.gz" : "zip"}`,
49
- );
50
- res.pipe(stream);
90
+ response.on("error", (error) => {
91
+ rej(error);
92
+ });
51
93
  });
52
94
  });
53
95
  };
@@ -1,4 +1,5 @@
1
1
  import { access, readFile, writeFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
2
3
 
3
4
  import { log } from "../log.js";
4
5
 
@@ -8,23 +9,37 @@ import { getManifest } from "./getManifest.js";
8
9
  * Get version specific release metadata
9
10
  *
10
11
  * @param {string} version NW version
12
+ * @param {string} platform NW platform
13
+ * @param {string} arch NW architecture
11
14
  * @param {string} cacheDir Directory to store NW binaries
12
15
  * @param {string} manifestUrl Url to manifest
13
16
  * @return {object} Version specific release info
14
17
  */
15
- export const getReleaseInfo = async (version, cacheDir, manifestUrl) => {
18
+ export const getReleaseInfo = async (
19
+ version,
20
+ platform,
21
+ arch,
22
+ cacheDir,
23
+ manifestUrl,
24
+ ) => {
16
25
  let releaseData = undefined;
26
+ let manifestPath = undefined;
27
+ if (platform === "osx" && arch === "arm64") {
28
+ manifestPath = resolve(cacheDir, "manifest.mac.arm.json");
29
+ } else {
30
+ manifestPath = resolve(cacheDir, "manifest.json");
31
+ }
17
32
  try {
18
- await access(`${cacheDir}/manifest.json`);
33
+ await access(manifestPath);
19
34
  log.debug(`Manifest file already exists locally under ${cacheDir}`);
20
35
  } catch (e) {
21
36
  log.debug(`Manifest file does not exist locally`);
22
37
  log.debug(`Downloading latest manifest file under ${cacheDir}`);
23
38
  const data = await getManifest(manifestUrl);
24
- await writeFile(`${cacheDir}/manifest.json`, data.slice(9));
39
+ await writeFile(manifestPath, data.slice(9));
25
40
  } finally {
26
41
  log.debug("Store manifest metadata in memory");
27
- let manifest = JSON.parse(await readFile(`${cacheDir}/manifest.json`));
42
+ let manifest = JSON.parse(await readFile(resolve(manifestPath)));
28
43
  log.debug(`Search for ${version} specific release data`);
29
44
  if (version === "latest" || version === "stable" || version === "lts") {
30
45
  // Remove leading "v" from version string
package/src/get/remove.js CHANGED
@@ -1,17 +1,34 @@
1
- import fs from "node:fs";
1
+ import { rm } from "node:fs/promises";
2
+ import { resolve } from "node:path";
2
3
 
3
- const remove = (platform, outDir) => {
4
- return new Promise((resolve, reject) => {
5
- fs.rm(
6
- `${outDir}/nw.${platform === "linux" ? "tar.gz" : "zip"}`,
7
- (error) => {
8
- if (error) {
9
- reject(error);
10
- }
11
- },
12
- );
13
- resolve(0);
14
- });
4
+ import { log } from "../log.js";
5
+
6
+ /**
7
+ * Remove NW.js binary
8
+ *
9
+ * @param {string} platform - linux, macos, win32
10
+ * @param {string} cacheDir - Output directory
11
+ * @param {string} downloadUrl - Download URL
12
+ * @return {Promise<void>} - Promise
13
+ */
14
+ const remove = async (platform, cacheDir, downloadUrl) => {
15
+ try {
16
+ if (downloadUrl === "https://dl.nwjs.io/") {
17
+ if (platform === "linux") {
18
+ await rm(resolve(cacheDir, "nw.tar.gz"));
19
+ } else {
20
+ await rm(resolve(cacheDir, "nw.zip"));
21
+ }
22
+ } else if (
23
+ downloadUrl ===
24
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download"
25
+ ) {
26
+ await rm(resolve(cacheDir, "ffmpeg.zip"));
27
+ }
28
+ } catch (error) {
29
+ log.error(error);
30
+ throw error;
31
+ }
15
32
  };
16
33
 
17
34
  export { remove };
package/src/nwbuild.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { mkdir, rm } from "node:fs/promises";
2
+ import { resolve } from "node:path";
2
3
 
3
4
  import { decompress } from "./get/decompress.js";
4
5
  import { download } from "./get/download.js";
@@ -7,10 +8,11 @@ import { remove } from "./get/remove.js";
7
8
  import { packager } from "./bld/package.js";
8
9
  import { develop } from "./run/develop.js";
9
10
  import { isCached } from "./util/cache.js";
10
- import { notify } from "./util/notify.js";
11
+ import { replaceFfmpeg } from "./util/ffmpeg.js";
11
12
  import { getOptions } from "./util/options.js";
12
13
  import { parse } from "./util/parse.js";
13
14
  import { validate } from "./util/validate.js";
15
+ import { xattr } from "./util/xattr.js";
14
16
 
15
17
  import { log } from "./log.js";
16
18
 
@@ -61,7 +63,7 @@ import { log } from "./log.js";
61
63
  * @property {"latest" | "stable" | string} [version="latest"] NW runtime version
62
64
  * @property {"normal" | "sdk"} [flavor="normal"] NW runtime build flavor
63
65
  * @property {"linux" | "osx" | "win"} platform NW supported platforms
64
- * @property {"ia32" | "x64"} arch NW supported architectures
66
+ * @property {"ia32" | "x64" | "arm64"} arch NW supported architectures
65
67
  * @property {string} [outDir="./out"] Directory to store build artifacts
66
68
  * @property {"./cache" | string} [cacheDir="./cache"] Directory to store NW binaries
67
69
  * @property {"https://dl.nwjs.io"} [downloadUrl="https://dl.nwjs.io"] URI to download NW binaries from
@@ -70,6 +72,7 @@ import { log } from "./log.js";
70
72
  * @property {boolean} [cache=true] If true the existing cache is used. Otherwise it removes and redownloads it.
71
73
  * @property {boolean} [zip=false] If true the outDir directory is zipped
72
74
  * @property {boolean} [cli=false] If true the CLI is used to glob srcDir and parse other options
75
+ * @property {boolean} [ffmpeg=false] If true the chromium ffmpeg is replaced by community version
73
76
  */
74
77
 
75
78
  /**
@@ -80,13 +83,12 @@ import { log } from "./log.js";
80
83
  */
81
84
  const nwbuild = async (options) => {
82
85
  let nwDir = "";
86
+ let ffmpegFile = "";
83
87
  let cached;
84
88
  let nwCached;
85
89
  let built;
86
90
  let releaseInfo = {};
87
91
 
88
- notify();
89
-
90
92
  try {
91
93
  const { opts, files, nwPkg } = await getOptions(options);
92
94
  options = opts;
@@ -109,6 +111,8 @@ const nwbuild = async (options) => {
109
111
  // Validate options.version to get the version specific release info
110
112
  releaseInfo = await getReleaseInfo(
111
113
  options.version,
114
+ options.platform,
115
+ options.arch,
112
116
  options.cacheDir,
113
117
  options.manifestUrl,
114
118
  );
@@ -118,9 +122,12 @@ const nwbuild = async (options) => {
118
122
  await validate(options, releaseInfo);
119
123
 
120
124
  // Variable to store nwDir file path
121
- nwDir = `${options.cacheDir}/nwjs${
122
- options.flavor === "sdk" ? "-sdk" : ""
123
- }-v${options.version}-${options.platform}-${options.arch}`;
125
+ nwDir = resolve(
126
+ options.cacheDir,
127
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${
128
+ options.platform
129
+ }-${options.arch}`,
130
+ );
124
131
 
125
132
  nwCached = await isCached(nwDir);
126
133
  // Remove cached NW binary
@@ -139,10 +146,57 @@ const nwbuild = async (options) => {
139
146
  options.downloadUrl,
140
147
  options.cacheDir,
141
148
  );
142
- await decompress(options.platform, options.cacheDir);
143
- await remove(options.platform, options.cacheDir);
149
+ await decompress(options.platform, options.cacheDir, options.downloadUrl);
150
+ await remove(options.platform, options.cacheDir, options.downloadUrl);
144
151
  }
145
152
 
153
+ if (options.ffmpeg === true) {
154
+ log.warn(
155
+ "Using MP3 and H.264 codecs requires you to pay attention to the patent royalties and the license of the source code. Consult a lawyer if you do not understand the licensing constraints and using patented media formats in your app. See https://chromium.googlesource.com/chromium/third_party/ffmpeg.git/+/master/CREDITS.chromium for more information.",
156
+ );
157
+ if (options.platform === "win") {
158
+ ffmpegFile = "libffmpeg.dll";
159
+ } else if (options.platform === "osx") {
160
+ ffmpegFile = "libffmpeg.dylib";
161
+ } else if (options.platform === "linux") {
162
+ ffmpegFile = "libffmpeg.so";
163
+ }
164
+ ffmpegFile = resolve(options.cacheDir, ffmpegFile);
165
+ const ffmpegCached = await isCached(ffmpegFile);
166
+ // Remove cached ffmpeg binary
167
+ if (options.cache === false && ffmpegCached === true) {
168
+ log.debug("Remove cached ffmpeg binary");
169
+ await rm(ffmpegFile, { force: true, recursive: true });
170
+ }
171
+
172
+ // Download relevant ffmpeg binaries
173
+ if (ffmpegCached === false) {
174
+ log.debug("Download relevant ffmpeg binaries");
175
+ await download(
176
+ options.version,
177
+ options.flavor,
178
+ options.platform,
179
+ options.arch,
180
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
181
+ options.cacheDir,
182
+ );
183
+ await decompress(
184
+ options.platform,
185
+ options.cacheDir,
186
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
187
+ );
188
+ await remove(
189
+ options.platform,
190
+ options.cacheDir,
191
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download",
192
+ );
193
+
194
+ await replaceFfmpeg(options.platform, nwDir, ffmpegFile);
195
+ }
196
+ }
197
+
198
+ await xattr(options.platform, options.arch, nwDir);
199
+
146
200
  if (options.mode === "run") {
147
201
  await develop(options.srcDir, nwDir, options.platform, options.argv);
148
202
  }
@@ -4,6 +4,7 @@ import { log } from "../log.js";
4
4
 
5
5
  /**
6
6
  * Executes the NW.js process
7
+ *
7
8
  * @param {string} srcDir The source directory
8
9
  * @param {string} nwPath The path to the NW.js executable
9
10
  * @param {string} argv The arguments to pass to the NW.js process
@@ -1,3 +1,9 @@
1
+ /**
2
+ * Get platform specific name of the executable
3
+ *
4
+ * @param {string} platform - Platform
5
+ * @return {string} - Platform specific name
6
+ */
1
7
  const getPlatformSpecificName = (platform) => {
2
8
  switch (platform) {
3
9
  case "linux":
package/src/util/arch.js CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Get user's computer architecture
3
3
  *
4
- * @param {string} arch Node's process.arch
5
- * @return {"ia32"| "x64" | "string"} NW.js supported architectures
4
+ * @param {string} arch Node's process.arch
5
+ * @return {"ia32"| "x64" | "arm64" | "string"} NW.js supported architectures
6
6
  */
7
7
  export const getArch = (arch) => {
8
8
  return arch;
@@ -0,0 +1,30 @@
1
+ import { copyFile } from "node:fs/promises";
2
+ import { resolve } from "node:path";
3
+
4
+ /**
5
+ * Replaces the ffmpeg file in the nwjs directory with the one provided
6
+ *
7
+ * @param {string} platform The platform to replace the ffmpeg file for
8
+ * @param {string} nwDir The directory of the nwjs installation
9
+ * @param {string} ffmpegFile The path to the ffmpeg file to replace with
10
+ */
11
+ export const replaceFfmpeg = async (platform, nwDir, ffmpegFile) => {
12
+ if (platform === "linux") {
13
+ await copyFile(ffmpegFile, resolve(nwDir, "lib", ffmpegFile));
14
+ } else if (platform === "win") {
15
+ await copyFile(ffmpegFile, resolve(nwDir, ffmpegFile));
16
+ } else if (platform === "osx") {
17
+ await copyFile(
18
+ ffmpegFile,
19
+ resolve(
20
+ nwDir,
21
+ "Contents",
22
+ "Frameworks",
23
+ "nwjs Framework.framework",
24
+ "Versions",
25
+ "Current",
26
+ ffmpegFile,
27
+ ),
28
+ );
29
+ }
30
+ };
@@ -1,5 +1,5 @@
1
1
  import { readFile } from "node:fs/promises";
2
- import { basename } from "node:path";
2
+ import { basename, resolve } from "node:path";
3
3
 
4
4
  import glob from "glob-promise";
5
5
 
@@ -26,6 +26,10 @@ export const getOptions = async (opts) => {
26
26
  files = [...patterns];
27
27
  }
28
28
 
29
+ files.forEach((file, index) => {
30
+ files[index] = resolve(file);
31
+ });
32
+
29
33
  // Try to find the first instance of the package.json
30
34
  for (const file of files) {
31
35
  if (basename(file) === "package.json" && nwPkg === undefined) {
@@ -0,0 +1,17 @@
1
+ {
2
+ "latest": "v0.70.0",
3
+ "stable": "v0.70.0",
4
+ "lts": "v0.70.0",
5
+ "versions": [
6
+ {
7
+ "version": "v0.70.0",
8
+ "date": "2022/11/30",
9
+ "files": ["osx-arm64"],
10
+ "flavors": ["normal", "sdk"],
11
+ "components": {
12
+ "node": "19.0.0",
13
+ "chromium": "107.0.5304.88"
14
+ }
15
+ }
16
+ ]
17
+ }
package/src/util/parse.js CHANGED
@@ -1,4 +1,5 @@
1
- import { arch, cwd, platform } from "node:process";
1
+ import { resolve } from "node:path";
2
+ import { arch, platform } from "node:process";
2
3
 
3
4
  import { getArch } from "./arch.js";
4
5
  import { getPlatform } from "./platform.js";
@@ -15,14 +16,14 @@ export const parse = async (options, pkg) => {
15
16
  options = { ...pkg.nwbuild };
16
17
  }
17
18
 
18
- options.srcDir = `${cwd()}/${options.srcDir}` ?? `${cwd()}/**/*`;
19
+ options.srcDir = resolve(options.srcDir) ?? resolve("./*");
19
20
  options.mode = options.mode ?? "build";
20
21
  options.version = options.version ?? "latest";
21
22
  options.flavor = options.flavor || "normal";
22
23
  options.platform = options.platform ?? getPlatform(platform);
23
24
  options.arch = options.arch ?? getArch(arch);
24
- options.outDir = options.outDir ?? "./out";
25
- options.cacheDir = options.cacheDir ?? `${cwd()}/cache`;
25
+ options.outDir = resolve(options.outDir) ?? resolve("./out");
26
+ options.cacheDir = resolve(options.cacheDir) ?? resolve("./cache");
26
27
  options.downloadUrl = options.downloadUrl ?? "https://dl.nwjs.io";
27
28
  options.manifestUrl = options.manifestUrl ?? "https://nwjs.io/versions";
28
29
  options.app = {};
@@ -66,5 +67,6 @@ export const parse = async (options, pkg) => {
66
67
  options.app.specialBuild = options.app.specialBuild ?? undefined;
67
68
  options.cache = options.cache ?? true;
68
69
  options.zip = options.zip ?? false;
70
+ options.ffmpeg = options.ffmpeg ?? false;
69
71
  return options;
70
72
  };
@@ -0,0 +1,30 @@
1
+ import { exec } from "node:child_process";
2
+ import { resolve } from "node:path";
3
+
4
+ import { log } from "../log.js";
5
+
6
+ /**
7
+ * Remove the quarantine attribute from the app bundle
8
+ *
9
+ * @param {string} platform - The platform to build for
10
+ * @param {string} arch - The arch to build for
11
+ * @param {string} nwDir - The path to the nw directory
12
+ * @return {Promise<void>} - A promise that resolves when the attribute is removed
13
+ */
14
+ export const xattr = (platform, arch, nwDir) => {
15
+ return new Promise((res, rej) => {
16
+ if (platform === "osx" && arch === "arm64") {
17
+ let app = resolve(nwDir, "nwjs.app");
18
+ exec(`sudo xattr -d com.apple.quarantine ${app}`, (err, stdout) => {
19
+ log.debug(stdout);
20
+ if (err) {
21
+ rej(err);
22
+ } else {
23
+ res();
24
+ }
25
+ });
26
+ } else {
27
+ res();
28
+ }
29
+ });
30
+ };
@@ -1,14 +0,0 @@
1
- import { createRequire } from "node:module";
2
- const require = createRequire(import.meta.url);
3
-
4
- import updateNotifier from "update-notifier";
5
-
6
- /**
7
- * Notify the user if there is a new version of the package available.
8
- *
9
- * @return {Promise<void>}
10
- */
11
- export const notify = async () => {
12
- const packageJson = require("../../package.json");
13
- updateNotifier({ pkg: packageJson }).notify();
14
- };