nw 0.85.0 → 0.86.0-sdk

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/src/get.js ADDED
@@ -0,0 +1,221 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import url from 'node:url';
4
+
5
+ import decompress from "./decompress.js";
6
+ import ffmpeg from "./ffmpeg.js";
7
+ import node from "./node.js";
8
+ import nw from "./nw.js";
9
+
10
+ import util from "./util.js";
11
+
12
+ /**
13
+ * @typedef {object} GetOptions
14
+ * @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
15
+ * @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
16
+ * @property {"linux" | "osx" | "win"} [platform] Target platform
17
+ * @property {"ia32" | "x64" | "arm64"} [arch] Target arch
18
+ * @property {string} [downloadUrl = "https://dl.nwjs.io"] Download server.
19
+ * @property {string} [cacheDir = "./cache"] Cache directory
20
+ * @property {boolean} [cache = true] If false, remove cache and redownload.
21
+ * @property {boolean} [ffmpeg = false] If true, ffmpeg is not downloaded.
22
+ * @property {false | "gyp"} [nativeAddon = false] Rebuild native modules
23
+ */
24
+
25
+ /**
26
+ * Get binaries.
27
+ *
28
+ * @async
29
+ * @function
30
+ * @param {GetOptions} options Get mode options
31
+ * @return {Promise<void>}
32
+ */
33
+ async function get(options) {
34
+
35
+ const uri = new url.URL(options.downloadUrl);
36
+
37
+ /* Download server is the cached directory. */
38
+ if (uri.protocol === 'file:') {
39
+ options.cacheDir = path.resolve(decodeURIComponent(options.downloadUrl.slice('file://'.length)));
40
+ }
41
+
42
+ /**
43
+ * If `options.cacheDir` exists, then `true`. Otherwise, it is `false`.
44
+ *
45
+ * @type {boolean}
46
+ */
47
+ const cacheDirExists = await util.fileExists(options.cacheDir);
48
+ if (cacheDirExists === false) {
49
+ await fs.promises.mkdir(options.cacheDir, { recursive: true });
50
+ }
51
+
52
+ /**
53
+ * File path to compressed binary.
54
+ *
55
+ * @type {string}
56
+ */
57
+ let nwFilePath = path.resolve(
58
+ options.cacheDir,
59
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}.${options.platform === "linux" ? "tar.gz" : "zip"
60
+ }`,
61
+ );
62
+
63
+ /**
64
+ * File path to directory which contain NW.js and related binaries.
65
+ *
66
+ * @type {string}
67
+ */
68
+ let nwDirPath = path.resolve(
69
+ options.cacheDir,
70
+ `nwjs${options.flavor === "sdk" ? "-sdk" : ""}-v${options.version}-${options.platform}-${options.arch}`,
71
+ );
72
+
73
+ // If `options.cache` is false, then remove the compressed binary.
74
+ if (options.cache === false) {
75
+ await fs.promises.rm(nwFilePath, {
76
+ recursive: true,
77
+ force: true,
78
+ });
79
+ }
80
+
81
+ // We remove the nwDir to prevent the edge case where you download with ffmpeg flag enabled
82
+ // but want a subsequent build with ffmpeg flag disabled. By removing the directory and
83
+ // decompressing it again, we prevent the community ffmpeg files from being left over.
84
+ // This is important since the community ffmpeg builds have specific licensing constraints.
85
+ await fs.promises.rm(nwDirPath, { recursive: true, force: true });
86
+
87
+ /**
88
+ * If the compressed binary exists, then `true`. Otherwise, it is `false`.
89
+ *
90
+ * @type {boolean}
91
+ */
92
+ const nwFilePathExists = await util.fileExists(nwFilePath);
93
+ if (nwFilePathExists === false) {
94
+ nwFilePath = await nw(options.downloadUrl, options.version, options.flavor, options.platform, options.arch, options.cacheDir);
95
+ }
96
+
97
+ await decompress(nwFilePath, options.cacheDir);
98
+
99
+ await fs.promises.symlink(nwDirPath, './nwjs', );
100
+
101
+ if (options.ffmpeg === true) {
102
+
103
+ /**
104
+ * File path to compressed binary which contains community FFmpeg binary.
105
+ *
106
+ * @type {string}
107
+ */
108
+ let ffmpegFilePath = path.resolve(
109
+ options.cacheDir,
110
+ `ffmpeg-${options.version}-${options.platform}-${options.arch}.zip`,
111
+ );
112
+
113
+ // If `options.cache` is false, then remove the compressed binary.
114
+ if (options.cache === false) {
115
+ await fs.promises.rm(ffmpegFilePath, {
116
+ recursive: true,
117
+ force: true,
118
+ });
119
+ }
120
+
121
+ /**
122
+ * If the compressed binary exists, then `true`. Otherwise, it is `false`.
123
+ *
124
+ * @type {boolean}
125
+ */
126
+ const ffmpegFilePathExists = await util.fileExists(ffmpegFilePath);
127
+ if (ffmpegFilePathExists === false) {
128
+ // Do not update the options.downloadUrl with the ffmpeg URL here. Doing so would lead to error when options.ffmpeg and options.nativeAddon are both enabled.
129
+ const downloadUrl =
130
+ "https://github.com/nwjs-ffmpeg-prebuilt/nwjs-ffmpeg-prebuilt/releases/download";
131
+ ffmpegFilePath = await ffmpeg(downloadUrl, options.version, options.platform, options.arch, options.cacheDir);
132
+ }
133
+
134
+ await decompress(ffmpegFilePath, options.cacheDir);
135
+
136
+ /**
137
+ * Platform dependant file name of FFmpeg binary.
138
+ *
139
+ * @type {string}
140
+ */
141
+ let ffmpegFileName = "";
142
+
143
+ if (options.platform === "linux") {
144
+ ffmpegFileName = "libffmpeg.so";
145
+ } else if (options.platform === "win") {
146
+ ffmpegFileName = "ffmpeg.dll";
147
+ } else if (options.platform === "osx") {
148
+ ffmpegFileName = "libffmpeg.dylib";
149
+ }
150
+
151
+ /**
152
+ * File path to platform specific FFmpeg file.
153
+ *
154
+ * @type {string}
155
+ */
156
+ let ffmpegBinaryPath = path.resolve(options.cacheDir, ffmpegFileName);
157
+
158
+ /**
159
+ * File path of where FFmpeg will be copied to.
160
+ *
161
+ * @type {string}
162
+ */
163
+ let ffmpegBinaryDest = "";
164
+
165
+ if (options.platform === "linux") {
166
+ ffmpegBinaryDest = path.resolve(nwDirPath, "lib", ffmpegFileName);
167
+ } else if (options.platform === "win") {
168
+ ffmpegBinaryDest = path.resolve(nwDirPath, ffmpegFileName);
169
+ } else if (options.platform === "osx") {
170
+ ffmpegBinaryDest = path.resolve(
171
+ nwDirPath,
172
+ "nwjs.app",
173
+ "Contents",
174
+ "Frameworks",
175
+ "nwjs Framework.framework",
176
+ "Versions",
177
+ "Current",
178
+ ffmpegFileName,
179
+ );
180
+ }
181
+
182
+ await fs.promises.copyFile(ffmpegBinaryPath, ffmpegBinaryDest);
183
+
184
+ }
185
+
186
+ if (options.nativeAddon === "gyp") {
187
+
188
+ /**
189
+ * File path to NW'js Node headers tarball.
190
+ *
191
+ * @type {string}
192
+ */
193
+ let nodeFilePath = path.resolve(
194
+ options.cacheDir,
195
+ `headers-v${options.version}.tar.gz`,
196
+ );
197
+
198
+ // If `options.cache` is false, then remove the compressed binary.
199
+ if (options.cache === false) {
200
+ await fs.promises.rm(nodeFilePath, {
201
+ recursive: true,
202
+ force: true,
203
+ });
204
+ }
205
+
206
+ /**
207
+ * If the compressed binary exists, then `true`. Otherwise, it is `false`.
208
+ *
209
+ * @type {boolean}
210
+ */
211
+ const nodeFilePathExists = await util.fileExists(nodeFilePath);
212
+ if (nodeFilePathExists === false) {
213
+ nodeFilePath = await node(options.downloadUrl, options.version, options.cacheDir);
214
+ }
215
+
216
+ await decompress(nodeFilePath, options.cacheDir);
217
+
218
+ }
219
+ }
220
+
221
+ export default get;
package/src/index.js ADDED
@@ -0,0 +1,11 @@
1
+ import get from './get.js';
2
+ import run from './run';
3
+ import util from './util.js';
4
+
5
+ const { findpath } = util;
6
+
7
+ export {
8
+ findpath,
9
+ get,
10
+ run,
11
+ }
package/src/node.js ADDED
@@ -0,0 +1,50 @@
1
+ import path from "node:path";
2
+
3
+ import request from "./request.js";
4
+
5
+ /**
6
+ * Download NW.js's Node.js headers.
7
+ *
8
+ * @param {string} downloadUrl - Download server
9
+ * @param {string} version - Runtime version
10
+ * @param {string} cacheDir - Directory to store NW binaries
11
+ * @return {Promise<string>} - path of compressed file which contains the Node headers.
12
+ */
13
+ export default async function nw(downloadUrl, version, cacheDir) {
14
+
15
+ /**
16
+ * Name of directory which contains Node headers.
17
+ *
18
+ * @type {string}
19
+ */
20
+ const nodeDir = `node-v${version}`;
21
+
22
+ /**
23
+ * Name of compressed file which contains Node headers.
24
+ *
25
+ * @type {string}
26
+ */
27
+ const nwFile = `${nodeDir}.tar.gz`
28
+
29
+ /**
30
+ * URL to download specific Node headers from.
31
+ *
32
+ * @type {string}
33
+ */
34
+ const url = [
35
+ downloadUrl,
36
+ `v${version}`,
37
+ `nw-headers-v${version}.tar.gz`
38
+ ].join('/');
39
+
40
+ /**
41
+ * Absolute path of compressed file which contains Node headers.
42
+ */
43
+ const nwFileAbs = path.resolve(
44
+ cacheDir,
45
+ nwFile
46
+ );
47
+ await request(url, nwFileAbs);
48
+
49
+ return nwFileAbs;
50
+ }
@@ -0,0 +1,24 @@
1
+ import fs from "node:fs";
2
+
3
+ import { afterEach, describe, expect, it } from "vitest";
4
+
5
+ import node from "./node.js";
6
+ import util from "./util.js";
7
+
8
+ describe("get/node", function () {
9
+
10
+ let nodeFile = '';
11
+
12
+ afterEach(function () {
13
+ fs.promises.rm(nodeFile, { recursive: true, force: true });
14
+ });
15
+
16
+ it("downloades Node headers", async function () {
17
+ nodeFile = await node(
18
+ "https://dl.nwjs.io",
19
+ "0.83.0",
20
+ "./test/fixture"
21
+ );
22
+ expect(util.fileExists(nodeFile)).resolves.toBe(true);
23
+ }, Infinity);
24
+ });
package/src/nw.js ADDED
@@ -0,0 +1,60 @@
1
+ import path from "node:path";
2
+
3
+ import request from "./request.js";
4
+
5
+ /**
6
+ * Download NW.js binary.
7
+ *
8
+ * @param {string} downloadUrl - Download server
9
+ * @param {string} version - Runtime version
10
+ * @param {string} flavor - Runtime build flavor
11
+ * @param {string} platform - NW supported platform
12
+ * @param {string} arch - NW supported architecture
13
+ * @param {string} cacheDir - Directory to store NW binaries
14
+ * @return {Promise<string>} - path of compressed file which contains NW.js binaries.
15
+ */
16
+ export default async function nw(downloadUrl, version, flavor, platform, arch, cacheDir) {
17
+
18
+ /**
19
+ * Name of directory which contains NW.js binaries.
20
+ *
21
+ * @type {string}
22
+ */
23
+ const nwDir = [
24
+ `nwjs`,
25
+ flavor === 'sdk' ? '-sdk' : '',
26
+ `-v${version}-${platform}-${arch}`,
27
+ ].join('');
28
+
29
+ /**
30
+ * Name of compressed file which contains NW.js binaries.
31
+ *
32
+ * @type {string}
33
+ */
34
+ const nwFile = [
35
+ nwDir,
36
+ platform === 'linux' ? "tar.gz" : "zip"
37
+ ].join('.');
38
+
39
+ /**
40
+ * URL to download specific NW.js binary from.
41
+ *
42
+ * @type {string}
43
+ */
44
+ const url = [
45
+ downloadUrl,
46
+ `v${version}`,
47
+ nwFile,
48
+ ].join('/');
49
+
50
+ /**
51
+ * Absolute path of compressed file which contains NW.js binaries.
52
+ */
53
+ const nwFileAbs = path.resolve(
54
+ cacheDir,
55
+ nwFile
56
+ );
57
+ await request(url, nwFileAbs);
58
+
59
+ return nwFileAbs;
60
+ }
package/src/nw.test.js ADDED
@@ -0,0 +1,28 @@
1
+ import fs from "node:fs";
2
+ import process from "node:process";
3
+
4
+ import { afterEach, describe, expect, it } from "vitest";
5
+
6
+ import nw from "./nw.js";
7
+ import util from "./util.js";
8
+
9
+ describe("get/nw", function () {
10
+
11
+ let nwFile = '';
12
+
13
+ afterEach(function () {
14
+ fs.promises.rm(nwFile, { recursive: true, force: true });
15
+ });
16
+
17
+ it("downloades a NW.js Linux tarball or Windows/MacOS zip", async function () {
18
+ nwFile = await nw(
19
+ "https://dl.nwjs.io",
20
+ "0.83.0",
21
+ "sdk",
22
+ util.PLATFORM_KV[process.platform],
23
+ util.ARCH_KV[process.arch],
24
+ "./test/fixture"
25
+ );
26
+ expect(util.fileExists(nwFile)).resolves.toBe(true);
27
+ }, Infinity);
28
+ });
package/src/parse.js ADDED
@@ -0,0 +1,65 @@
1
+ import process from 'node:process';
2
+
3
+ import semver from 'semver';
4
+
5
+ import nodeManifest from '../package.json' assert { type: 'json' };
6
+ import util from '../src/util.js';
7
+
8
+ /**
9
+ * @typedef {object} ParseOptions
10
+ * @property {string | "latest" | "stable" | "lts"} version Runtime version
11
+ * @property {"normal" | "sdk"} flavor Build flavor
12
+ * @property {"linux" | "osx" | "win"} platform Target platform
13
+ * @property {"ia32" | "x64" | "arm64"} arch Target arch
14
+ * @property {string} downloadUrl Download server.
15
+ * @property {string} cacheDir Cache directory
16
+ * @property {boolean} cache If false, remove cache and redownload.
17
+ * @property {boolean} ffmpeg If true, ffmpeg is not downloaded.
18
+ * @property {false | "gyp"} nativeAddon Rebuild native modules
19
+ */
20
+
21
+ /**
22
+ * Parse options.
23
+ *
24
+ * @param {ParseOptions} options
25
+ * @return {Promise<ParseOptions>}
26
+ */
27
+ export default async function parse(options) {
28
+ options.version = options.version ?? nodeManifest.version;
29
+ const parsedVersion = semver.parse(options.version);
30
+ options.version = [
31
+ parsedVersion.major,
32
+ parsedVersion.minor,
33
+ parsedVersion.patch
34
+ ].join('.');
35
+
36
+ options.flavor = options.flavor || process.env.npm_config_nwjs_build_type || process.env.NWJS_BUILD_TYPE || 'normal';
37
+
38
+ /* Check if version is a prelease. */
39
+ if (typeof parsedVersion?.prerelease?.[0] === 'string') {
40
+ let prerelease = parsedVersion.prerelease[0].split('-');
41
+ if (prerelease.length > 1) {
42
+ prerelease = prerelease.slice(0, -1);
43
+ }
44
+ options.version = [options.version, ...prerelease].join('-');
45
+ }
46
+
47
+ /* Check build flavor and slice that off the `version`. */
48
+ if (options.version.endsWith('-sdk')) {
49
+ options.version = options.version.slice(0, -4);
50
+ options.flavor = 'sdk';
51
+ } else if (options.version.endsWith('sdk')) {
52
+ options.version = version.slice(0, -3);
53
+ options.flavor = 'sdk';
54
+ }
55
+
56
+ options.platform = options.platform || util.PLATFORM_KV[process.env.npm_config_nwjs_platform || process.env.NWJS_PLATFORM || process.platform];
57
+ options.arch = options.arch || util.ARCH_KV[process.env.npm_config_nwjs_process_arch || process.env.NWJS_ARCH || process.arch];
58
+ options.downloadUrl = options.downloadUrl || process.env.npm_config_nwjs_urlbase || process.env.NWJS_URLBASE || 'https://dl.nwjs.io';
59
+ options.cacheDir = options.npm_config_nwjs_urlbase || process.env.npm_config_nwjs_cache_dir || process.env.NWJS_CACHE_DIR || '.';
60
+ options.cache = options.cache || process.env.npm_config_nwjs_cache || process.env.NWJS_CACHE || true;
61
+ options.ffmpeg = options.ffmpeg || process.env.npm_config_nwjs_ffmpeg || process.env.NWJS_FFMPEG || false;
62
+ options.nativeAddon = options.nativeAddon || process.env.npm_config_nwjs_native_addon || process.env.NWJS_NATIVE_ADDON || false;
63
+
64
+ return { ...options };
65
+ }
@@ -0,0 +1,63 @@
1
+ import process from 'node:process';
2
+
3
+ import semver from 'semver';
4
+
5
+ import get from './get.js';
6
+ import util from './util.js';
7
+
8
+ import nodeManifest from '../package.json' assert { type: 'json' };
9
+
10
+ await postinstall()
11
+ .catch((error) => {
12
+ if (error.code === 'EPERM') {
13
+ console.error('Unable to create symlink since user did not run as Administrator.');
14
+ }
15
+ });
16
+
17
+ async function postinstall() {
18
+ const parsedVersion = semver.parse(nodeManifest.version);
19
+ let version = [
20
+ parsedVersion.major,
21
+ parsedVersion.minor,
22
+ parsedVersion.patch
23
+ ].join('.');
24
+
25
+ let flavor = process.env.npm_config_nwjs_build_type || process.env.NWJS_BUILD_TYPE || 'normal';
26
+ /* Check if version is a prelease. */
27
+ if (typeof parsedVersion?.prerelease?.[0] === 'string') {
28
+ let prerelease = parsedVersion.prerelease[0].split('-');
29
+ if (prerelease.length > 1) {
30
+ prerelease = prerelease.slice(0, -1);
31
+ }
32
+ version = [version, ...prerelease].join('-');
33
+ }
34
+
35
+ /* Check build flavor and slice that off the `version`. */
36
+ if (version.endsWith('-sdk')) {
37
+ version = version.slice(0, -4);
38
+ flavor = 'sdk';
39
+ } else if (version.endsWith('sdk')) {
40
+ version = version.slice(0, -3);
41
+ flavor = 'sdk';
42
+ }
43
+
44
+ const platform = util.PLATFORM_KV[process.env.npm_config_nwjs_platform || process.env.NWJS_PLATFORM || process.platform];
45
+ const arch = util.ARCH_KV[process.env.npm_config_nwjs_process_arch || process.env.NWJS_ARCH || process.arch];
46
+ const downloadUrl = process.env.npm_config_nwjs_urlbase || process.env.NWJS_URLBASE || 'https://dl.nwjs.io';
47
+ const cacheDir = process.env.npm_config_nwjs_cache_dir || process.env.NWJS_CACHE_DIR || '.';
48
+ const cache = process.env.npm_config_nwjs_cache || process.env.NWJS_CACHE || true;
49
+ const ffmpeg = process.env.npm_config_nwjs_ffmpeg || process.env.NWJS_FFMPEG || false;
50
+ const nativeAddon = process.env.npm_config_nwjs_native_addon || process.env.NWJS_NATIVE_ADDON || false;
51
+
52
+ await get({
53
+ version,
54
+ flavor,
55
+ platform,
56
+ arch,
57
+ downloadUrl,
58
+ cacheDir,
59
+ cache,
60
+ ffmpeg: ffmpeg,
61
+ nativeAddon: nativeAddon
62
+ });
63
+ }
package/src/request.js ADDED
@@ -0,0 +1,27 @@
1
+ import fs from "node:fs";
2
+ import stream from "node:stream";
3
+
4
+ import axios from "axios";
5
+
6
+ /**
7
+ * Download from `url`.
8
+ *
9
+ * @async
10
+ * @function
11
+ *
12
+ * @param {string} url - Download server
13
+ * @param {string} filePath - file path of downloaded content
14
+ * @return {Promise<void>}
15
+ */
16
+ export default async function request(url, filePath) {
17
+
18
+ const writeStream = fs.createWriteStream(filePath);
19
+
20
+ const response = await axios({
21
+ method: "get",
22
+ url: url,
23
+ responseType: "stream"
24
+ });
25
+
26
+ await stream.promises.pipeline(response.data, writeStream);
27
+ }
@@ -0,0 +1,25 @@
1
+ import fs from "node:fs";
2
+
3
+ import { afterEach, beforeAll, describe, expect, it } from "vitest";
4
+
5
+ import request from "./request.js";
6
+ import util from "./util.js";
7
+
8
+ describe("get/request", function () {
9
+
10
+ let url = "https://raw.githubusercontent.com/nwutils/nw-builder/main/src/util/osx.arm.versions.json"
11
+ const filePath = "./test/fixture/request.test.json";
12
+
13
+ afterEach(async function () {
14
+ await fs.promises.rm(filePath, { force: true });
15
+ });
16
+
17
+ beforeAll(async function () {
18
+ await fs.promises.mkdir('./test/fixture', { recursive: true });
19
+ });
20
+
21
+ it("downloads from specific url", async function () {
22
+ await request(url, filePath);
23
+ expect(util.fileExists(filePath)).resolves.toBe(true);
24
+ }, Infinity);
25
+ });
package/src/run.js ADDED
@@ -0,0 +1,66 @@
1
+ import child_process from "node:child_process";
2
+ import console from "node:console";
3
+ import path from "node:path";
4
+ import process from "node:process";
5
+
6
+ import util from "./util.js";
7
+
8
+ /**
9
+ * @typedef {object} RunOptions
10
+ * @property {string | "latest" | "stable" | "lts"} [version = "latest"] Runtime version
11
+ * @property {"normal" | "sdk"} [flavor = "normal"] Build flavor
12
+ * @property {"linux" | "osx" | "win"} [platform] Target platform
13
+ * @property {"ia32" | "x64" | "arm64"} [arch] Target arch
14
+ * @property {string} [srcDir = "./src"] Source directory
15
+ * @property {string} [cacheDir = "./cache"] Cache directory
16
+ */
17
+
18
+ /**
19
+ * Run NW.js application.
20
+ *
21
+ * @async
22
+ * @function
23
+ *
24
+ * @param {RunOptions} options Run mode options
25
+ * @return {Promise<void>}
26
+ */
27
+ async function run({
28
+ version = "latest",
29
+ flavor = "normal",
30
+ platform = util.PLATFORM_KV[process.platform],
31
+ arch = util.ARCH_KV[process.arch],
32
+ srcDir = ".",
33
+ cacheDir = "./cache",
34
+ }) {
35
+
36
+ try {
37
+ if (util.EXE_NAME[platform] === undefined) {
38
+ throw new Error("Unsupported platform.");
39
+ }
40
+
41
+ const nwDir = path.resolve(
42
+ cacheDir,
43
+ `nwjs${flavor === "sdk" ? "-sdk" : ""}-v${version}-${platform}-${arch}`,
44
+ );
45
+
46
+ return new Promise((res, rej) => {
47
+ const nwProcess = child_process.spawn(
48
+ path.resolve(nwDir, util.EXE_NAME[platform]),
49
+ [srcDir]
50
+ );
51
+
52
+ nwProcess.on("close", () => {
53
+ res();
54
+ });
55
+
56
+ nwProcess.on("error", (error) => {
57
+ console.error(error);
58
+ rej(error);
59
+ });
60
+ });
61
+ } catch (error) {
62
+ console.error(error);
63
+ }
64
+ }
65
+
66
+ export default run;