@lakutata/builder 3.1.1 → 3.1.5

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.
@@ -0,0 +1,149 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { cp, mkdir, mkdtemp, readFile, rename, rm, writeFile } from 'node:fs/promises';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { programName } from '../Bundle.js';
6
+ import { applicationIcon, icnsFile, icoFile, setExecutableIcon } from '../Icons.js';
7
+ import { runCommand } from '../Processes.js';
8
+ import { downloadNwjs } from './Runtime.js';
9
+ import { stageNwjsApp } from './Stage.js';
10
+ /**
11
+ * Run a command which must succeed
12
+ * @param command
13
+ * @param args
14
+ * @param cwd
15
+ * @param what
16
+ */
17
+ async function must(command, args, cwd, what) {
18
+ const result = await runCommand(command, args, cwd);
19
+ if (result.code !== 0)
20
+ throw new Error(`${what}: ${result.output.trim()}`);
21
+ }
22
+ /**
23
+ * Give the files of an application to every user: readable, its directories and its programs runnable. The archives of
24
+ * the older releases of NW.js (0.72) give their files to their owner only: installed by root (/opt, /Applications), the
25
+ * application would run for root only. The files of Windows have no modes
26
+ * @param directory
27
+ */
28
+ async function shareFiles(directory) {
29
+ if (process.platform !== 'win32')
30
+ await must('chmod', ['-R', 'a+rX', directory], directory, 'The files of the application cannot be given to every user');
31
+ }
32
+ /**
33
+ * The four numbers of a version of Windows (1.2.3 → 1.2.3.0)
34
+ * @param version
35
+ */
36
+ function windowsVersion(version) {
37
+ const parts = version.split(/[.+-]/).slice(0, 3).map((part) => Math.min(parseInt(part, 10) || 0, 65535));
38
+ return [parts[0] ?? 0, parts[1] ?? 0, parts[2] ?? 0, 0];
39
+ }
40
+ /**
41
+ * Give the executable of NW.js of Windows the identity of the application: its icon, and the names and the version of its
42
+ * version information (the ones the task manager and the properties of the file show)
43
+ * @param file
44
+ * @param identity
45
+ */
46
+ async function windowsIdentity(file, identity) {
47
+ if (identity.ico)
48
+ await setExecutableIcon(file, identity.ico);
49
+ const { NtExecutable, NtExecutableResource, Resource } = await import('resedit');
50
+ const executable = NtExecutable.from(await readFile(file), { ignoreCert: true });
51
+ const resource = NtExecutableResource.from(executable);
52
+ const information = Resource.VersionInfo.fromEntries(resource.entries)[0] ?? Resource.VersionInfo.createEmpty();
53
+ const numbers = windowsVersion(identity.version);
54
+ information.setFileVersion(...numbers);
55
+ information.setProductVersion(...numbers);
56
+ const languages = information.getAllLanguagesForStringValues();
57
+ for (const language of languages.length ? languages : [{ lang: 1033, codepage: 1200 }]) {
58
+ information.setStringValues(language, {
59
+ FileDescription: identity.productName,
60
+ ProductName: identity.productName,
61
+ CompanyName: identity.company,
62
+ InternalName: identity.program,
63
+ OriginalFilename: `${identity.program}.exe`,
64
+ FileVersion: identity.version,
65
+ ProductVersion: identity.version
66
+ });
67
+ }
68
+ information.outputToResourceEntries(resource.entries);
69
+ resource.outputResource(executable);
70
+ await writeFile(file, Buffer.from(executable.generate()));
71
+ }
72
+ /**
73
+ * Make the application of NW.js of a project for this system: the runtime of NW.js (normal) with the application
74
+ * (stageNwjsApp: its bundle, its native addons made to load in NW.js, its resources, its manifest), named after it.
75
+ * On Windows and Linux, the files of the application are next to its executable (nw.exe, nw renamed after its program:
76
+ * the name of its installers, lakutata.installer.name, else the program of its package; on Windows, its icon and its
77
+ * version information are the ones of the application); on macOS, they are in the bundle
78
+ * (<product>.app/Contents/Resources/app.nw), whose Info.plist gives its name, its identifier (the appId of the
79
+ * installer), its version and its icon, signed again (ad hoc). The icon is lakutata.icon. Its files are readable by
80
+ * every user, its programs runnable (once installed by root, the application runs for the users)
81
+ * @param options
82
+ * @example
83
+ * import {buildNwjsApp} from '@lakutata/builder'
84
+ *
85
+ * //dist/nwjs/desk-osx-arm64/Desk.app on a Mac with Apple silicon
86
+ * const app = await buildNwjsApp({})
87
+ * console.log(app.directory, app.runtime.version)
88
+ */
89
+ export async function buildNwjsApp(options) {
90
+ const project = path.resolve(options.project ?? process.cwd());
91
+ const manifest = JSON.parse(await readFile(path.join(project, 'package.json'), 'utf8'));
92
+ //The program is named after the package of its installers, else after the program of the package (the package of an
93
+ //application of a workspace is often named app)
94
+ const program = String(manifest.lakutata?.installer?.name ?? programName(manifest));
95
+ const productName = String(manifest.productName ?? manifest.lakutata?.installer?.productName ?? program);
96
+ const work = await mkdtemp(path.join(os.tmpdir(), 'lakutata-nwjs-app-'));
97
+ try {
98
+ const stage = await stageNwjsApp({ ...options, project: project, outdir: path.join(work, 'app'), minify: options.minify ?? true });
99
+ const runtime = await downloadNwjs({ version: stage.release.version, flavor: 'normal', platform: options.platform, arch: options.arch });
100
+ const directory = path.join(path.resolve(project, options.outdir ?? path.join('dist', 'nwjs')), `${program}-${runtime.platform}`);
101
+ await rm(directory, { recursive: true, force: true });
102
+ await mkdir(directory, { recursive: true });
103
+ const icon = applicationIcon(project, manifest);
104
+ const version = String(manifest.version ?? '0.0.0');
105
+ if (runtime.platform.startsWith('osx-')) {
106
+ //ditto keeps the links of the frameworks and the signatures of the helpers
107
+ const bundle = path.join(directory, `${productName}.app`);
108
+ await must('ditto', [path.join(runtime.directory, 'nwjs.app'), bundle], directory, 'The bundle of macOS cannot be copied');
109
+ await must('ditto', [stage.directory, path.join(bundle, 'Contents', 'Resources', 'app.nw')], directory, 'The application cannot be copied into the bundle');
110
+ const plist = path.join(bundle, 'Contents', 'Info.plist');
111
+ const appId = String(manifest.lakutata?.installer?.appId ?? `com.${program}.app`);
112
+ for (const [key, value] of Object.entries({ CFBundleName: productName, CFBundleDisplayName: productName, CFBundleIdentifier: appId, CFBundleShortVersionString: version, CFBundleVersion: version })) {
113
+ await must('plutil', ['-replace', key, '-string', value, plist], directory, `${key} cannot be written into the Info.plist`);
114
+ }
115
+ if (icon)
116
+ await writeFile(path.join(bundle, 'Contents', 'Resources', 'app.icns'), icnsFile(icon.image));
117
+ await shareFiles(bundle);
118
+ //Its files changed, the bundle is signed again (ad hoc: the signature of a developer is given by its installer)
119
+ await must('codesign', ['--force', '--deep', '--sign', '-', bundle], directory, 'The bundle cannot be signed');
120
+ return { directory: bundle, executable: path.join(bundle, 'Contents', 'MacOS', 'nwjs'), program: program, productName: productName, runtime: runtime, stage: stage };
121
+ }
122
+ //The links of the runtime of Linux kept as they are (cp -a); the runtime of Windows has none
123
+ for (const source of [runtime.directory, stage.directory]) {
124
+ if (process.platform === 'win32')
125
+ await cp(source, directory, { recursive: true });
126
+ else
127
+ await must('cp', ['-a', `${source}/.`, directory], directory, 'The application cannot be copied');
128
+ }
129
+ const windows = runtime.platform.startsWith('win-');
130
+ const executable = path.join(directory, windows ? `${program}.exe` : program);
131
+ await rename(path.join(directory, windows ? 'nw.exe' : 'nw'), executable);
132
+ if (windows) {
133
+ await windowsIdentity(executable, {
134
+ productName: productName,
135
+ program: program,
136
+ version: version,
137
+ company: String(manifest.lakutata?.installer?.vendor ?? (typeof manifest.author === 'string' ? manifest.author : manifest.author?.name) ?? productName),
138
+ ico: icon && icoFile(icon.image)
139
+ });
140
+ }
141
+ if (!existsSync(executable))
142
+ throw new Error(`The executable of NW.js ${runtime.version} (${runtime.platform}) is missing`);
143
+ await shareFiles(directory);
144
+ return { directory: directory, executable: executable, program: program, productName: productName, runtime: runtime, stage: stage };
145
+ }
146
+ finally {
147
+ await rm(work, { recursive: true, force: true });
148
+ }
149
+ }
@@ -0,0 +1,214 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { existsSync } from 'node:fs';
3
+ import { mkdir, mkdtemp, open, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
4
+ import path from 'node:path';
5
+ import { runCommand } from '../Processes.js';
6
+ import { cacheDirectory } from '../Tools.js';
7
+ /**
8
+ * The oldest Node.js lakutata runs on: the releases of NW.js embedding an older one are refused
9
+ */
10
+ const OLDEST_NODE = '18.10.0';
11
+ /**
12
+ * The aliases of the versions
13
+ */
14
+ const ALIASES = { win7: '0.72.0' };
15
+ /**
16
+ * The releases are read again after a day
17
+ */
18
+ const RELEASES_TTL = 24 * 60 * 60 * 1000;
19
+ /**
20
+ * Where the releases are downloaded from: LAKUTATA_NWJS_MIRROR (a mirror of dl.nwjs.io), else dl.nwjs.io
21
+ */
22
+ function mirror() {
23
+ return (process.env.LAKUTATA_NWJS_MIRROR ?? 'https://dl.nwjs.io').replace(/\/+$/, '');
24
+ }
25
+ /**
26
+ * Compare two versions (1.2.3)
27
+ * @param left
28
+ * @param right
29
+ */
30
+ export function compareVersions(left, right) {
31
+ const parts = (version) => version.replace(/^v/, '').split('.').map((part) => parseInt(part, 10) || 0);
32
+ const [a, b] = [parts(left), parts(right)];
33
+ for (let index = 0; index < Math.max(a.length, b.length); index++) {
34
+ const difference = (a[index] ?? 0) - (b[index] ?? 0);
35
+ if (difference)
36
+ return difference;
37
+ }
38
+ return 0;
39
+ }
40
+ /**
41
+ * The releases of NW.js, newest first: the list of nwjs.io (LAKUTATA_NWJS_VERSIONS), kept a day in the cache; the
42
+ * cached one when it cannot be read
43
+ * @example
44
+ * import {nwjsReleases} from '@lakutata/builder'
45
+ *
46
+ * for (const release of (await nwjsReleases()).slice(0, 3)) console.log(release.version, release.node, release.chromium)
47
+ */
48
+ export async function nwjsReleases() {
49
+ const cache = path.join(cacheDirectory(), 'nwjs', 'versions.json');
50
+ const fresh = existsSync(cache) && Date.now() - (await stat(cache)).mtimeMs < RELEASES_TTL;
51
+ let list;
52
+ if (!fresh) {
53
+ try {
54
+ const response = await fetch(process.env.LAKUTATA_NWJS_VERSIONS ?? 'https://nwjs.io/versions.json');
55
+ if (!response.ok)
56
+ throw new Error(`${response.status}`);
57
+ list = await response.json();
58
+ await mkdir(path.dirname(cache), { recursive: true });
59
+ await writeFile(cache, JSON.stringify(list));
60
+ }
61
+ catch (error) {
62
+ if (!existsSync(cache))
63
+ throw new Error(`The releases of NW.js cannot be read (${error.message}): LAKUTATA_NWJS_VERSIONS gives another list`, { cause: error });
64
+ }
65
+ }
66
+ list ??= JSON.parse(await readFile(cache, 'utf8'));
67
+ const versions = list.versions ?? [];
68
+ return versions.map((entry) => ({
69
+ version: String(entry.version).replace(/^v/, ''),
70
+ date: String(entry.date ?? ''),
71
+ node: String(entry.components?.node ?? ''),
72
+ chromium: String(entry.components?.chromium ?? ''),
73
+ platforms: (entry.files ?? []).map((file) => String(file).replace(/-symbol$/, '')).filter((file) => /^(win|osx|linux)-/.test(file))
74
+ })).sort((a, b) => compareVersions(b.version, a.version));
75
+ }
76
+ /**
77
+ * A release of NW.js: a version, latest (the latest release) or win7 (0.72.0, the last one running on Windows 7, 8
78
+ * and 8.1). Refused when it embeds a Node.js older than the one lakutata runs on (18.10)
79
+ * @param version
80
+ * @example
81
+ * import {nwjsRelease} from '@lakutata/builder'
82
+ *
83
+ * const release = await nwjsRelease('win7')
84
+ * console.log(release.version, release.node, release.chromium) //0.72.0 19.3.0 109.0.5414.87
85
+ */
86
+ export async function nwjsRelease(version) {
87
+ const releases = await nwjsReleases();
88
+ const wanted = ALIASES[version] ?? version.replace(/^v/, '');
89
+ const release = wanted === 'latest' ? releases[0] : releases.find((item) => item.version === wanted);
90
+ if (!release)
91
+ throw new Error(`NW.js ${version} is not a release of NW.js (the latest: ${releases[0]?.version})`);
92
+ if (compareVersions(release.node, OLDEST_NODE) < 0)
93
+ throw new Error(`NW.js ${release.version} embeds Node.js ${release.node}: lakutata runs on Node.js ${OLDEST_NODE} or later (NW.js 0.70.0 or later)`);
94
+ return release;
95
+ }
96
+ /**
97
+ * The system and the architecture of a release as NW.js names them (osx-arm64), the x64 build on a Mac with Apple
98
+ * silicon when the release has no arm64 one
99
+ * @param release
100
+ * @param platform
101
+ * @param arch
102
+ */
103
+ export function nwjsPlatform(release, platform = process.platform, arch = process.arch) {
104
+ const system = { win32: 'win', darwin: 'osx', linux: 'linux' }[platform];
105
+ if (!system)
106
+ throw new Error(`NW.js has no build for ${platform}`);
107
+ const name = `${system}-${arch}`;
108
+ if (release.platforms.includes(name))
109
+ return name;
110
+ if (system === 'osx' && arch === 'arm64' && release.platforms.includes('osx-x64'))
111
+ return 'osx-x64';
112
+ throw new Error(`NW.js ${release.version} has no build for ${name} (${release.platforms.join(', ')})`);
113
+ }
114
+ /**
115
+ * The sha256 of the files of a release, from its SHASUMS256.txt
116
+ * @param version
117
+ */
118
+ async function checksums(version) {
119
+ const url = `${mirror()}/v${version}/SHASUMS256.txt`;
120
+ const response = await fetch(url);
121
+ if (!response.ok)
122
+ throw new Error(`The checksums of NW.js ${version} cannot be read (${url}: ${response.status})`);
123
+ const sums = new Map();
124
+ for (const line of (await response.text()).split('\n')) {
125
+ const match = line.trim().match(/^([0-9a-f]{64})\s+\*?(.+)$/);
126
+ if (match)
127
+ sums.set(match[2], match[1]);
128
+ }
129
+ return sums;
130
+ }
131
+ /**
132
+ * Download a file, its sha256 computed while it is written
133
+ * @param url
134
+ * @param file
135
+ */
136
+ async function download(url, file) {
137
+ const response = await fetch(url);
138
+ if (!response.ok || !response.body)
139
+ throw new Error(`${url} cannot be downloaded (${response.status})`);
140
+ const hash = createHash('sha256');
141
+ const handle = await open(file, 'w');
142
+ try {
143
+ for await (const chunk of response.body) {
144
+ hash.update(chunk);
145
+ await handle.write(chunk);
146
+ }
147
+ }
148
+ finally {
149
+ await handle.close();
150
+ }
151
+ return hash.digest('hex');
152
+ }
153
+ /**
154
+ * The executable of a runtime in its directory
155
+ * @param platform
156
+ */
157
+ function executableOf(platform) {
158
+ if (platform.startsWith('win-'))
159
+ return 'nw.exe';
160
+ if (platform.startsWith('osx-'))
161
+ return path.join('nwjs.app', 'Contents', 'MacOS', 'nwjs');
162
+ return 'nw';
163
+ }
164
+ /**
165
+ * A runtime of NW.js for a system, downloaded once into the cache (~/.cache/lakutata/nwjs, LAKUTATA_CACHE_DIR) from
166
+ * dl.nwjs.io (LAKUTATA_NWJS_MIRROR: a mirror of it) and checked with the SHASUMS256.txt of its release
167
+ * @param options
168
+ * @example
169
+ * import {downloadNwjs} from '@lakutata/builder'
170
+ *
171
+ * //The NW.js of the development (its developer tools), for the machine
172
+ * const runtime = await downloadNwjs({version: 'latest', flavor: 'sdk'})
173
+ * console.log(runtime.executable, runtime.node)
174
+ */
175
+ export async function downloadNwjs(options) {
176
+ const release = await nwjsRelease(options.version);
177
+ const flavor = options.flavor ?? 'normal';
178
+ const platform = nwjsPlatform(release, options.platform, options.arch);
179
+ const name = `nwjs${flavor === 'sdk' ? '-sdk' : ''}-v${release.version}-${platform}`;
180
+ const archive = `${name}.${platform.startsWith('linux-') ? 'tar.gz' : 'zip'}`;
181
+ const target = path.join(cacheDirectory(), 'nwjs', name);
182
+ const runtime = { ...release, flavor: flavor, platform: platform, directory: target, executable: path.join(target, executableOf(platform)) };
183
+ if (existsSync(runtime.executable))
184
+ return runtime;
185
+ const sum = (await checksums(release.version)).get(archive);
186
+ if (!sum)
187
+ throw new Error(`NW.js ${release.version} has no ${archive} in its checksums`);
188
+ //Extracted aside, then renamed: the builds running together do not see it partly written
189
+ await mkdir(path.dirname(target), { recursive: true });
190
+ const temporary = await mkdtemp(`${target}.`);
191
+ try {
192
+ const file = path.join(temporary, archive);
193
+ const downloaded = await download(`${mirror()}/v${release.version}/${archive}`, file);
194
+ if (downloaded !== sum)
195
+ throw new Error(`The ${archive} downloaded is not the one of NW.js ${release.version} (sha256 ${downloaded}, ${sum} expected)`);
196
+ //ditto keeps the links of the frameworks of macOS; the tar of Windows reads the zip archives
197
+ const extracted = process.platform === 'darwin' && archive.endsWith('.zip')
198
+ ? await runCommand('ditto', ['-x', '-k', archive, '.'], temporary)
199
+ : await runCommand('tar', ['-xf', archive], temporary);
200
+ if (extracted.code !== 0)
201
+ throw new Error(`${archive} cannot be extracted: ${extracted.output.trim()}`);
202
+ if (!existsSync(path.join(temporary, name, executableOf(platform))))
203
+ throw new Error(`${archive} has no ${name}/${executableOf(platform).split(path.sep).join('/')}`);
204
+ await rename(path.join(temporary, name), target).catch((error) => {
205
+ //Extracted by another build
206
+ if (!existsSync(runtime.executable))
207
+ throw error;
208
+ });
209
+ }
210
+ finally {
211
+ await rm(temporary, { recursive: true, force: true });
212
+ }
213
+ return runtime;
214
+ }
@@ -0,0 +1,92 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { mkdir, readFile, rm, writeFile } from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { bundleProject } from '../Bundle.js';
5
+ import { nwjsPlatform, nwjsRelease } from './Runtime.js';
6
+ import { prepareNwjsAddons } from './Addons.js';
7
+ /**
8
+ * The background script of the application in NW.js: its Node.js context, where the application runs. Its timers are
9
+ * the ones of Node.js: the older releases (0.72) give the background page the timers of the browser, whose ids are
10
+ * numbers (without unref and refresh)
11
+ */
12
+ const BACKGROUND_SCRIPT = `//The background script of the application in NW.js (its Node.js context): the timers of Node.js, then the application, bundled
13
+ const timers = require('timers')
14
+ for (const name of ['setTimeout', 'clearTimeout', 'setInterval', 'clearInterval', 'setImmediate', 'clearImmediate']) globalThis[name] = timers[name]
15
+ require('./app.cjs')
16
+ `;
17
+ /**
18
+ * The NW.js of an application, from the "lakutata.nwjs" of its package.json
19
+ * @param manifest
20
+ */
21
+ export function nwjsConfig(manifest) {
22
+ const config = manifest.lakutata?.nwjs;
23
+ if (!config || typeof config !== 'object' || typeof config.version !== 'string')
24
+ throw new Error('The application has no version of NW.js: give it with lakutata nwjs use <version> (latest, win7, 0.119.2…), which writes "lakutata": {"nwjs": {"version": …}} into its package.json');
25
+ return config;
26
+ }
27
+ /**
28
+ * The name of an application in NW.js: lower case, the characters of the names of the packages
29
+ * @param manifest
30
+ * @param config
31
+ */
32
+ function nwjsName(manifest, config) {
33
+ const name = String(config.name ?? manifest.lakutata?.installer?.appId ?? manifest.name ?? 'app');
34
+ return name.toLowerCase().replace(/^@/, '').replace(/[^a-z0-9._-]+/g, '-');
35
+ }
36
+ /**
37
+ * Make the application of NW.js of a project: its bundle (CommonJS, for the Node.js of the release), its native tree
38
+ * and its resources (lakutata.resources), the manifest of NW.js (its name, its background script, the partition of the
39
+ * webviews holding its user interface) and the background script running the bundle
40
+ * @param options
41
+ * @example
42
+ * import {stageNwjsApp} from '@lakutata/builder'
43
+ *
44
+ * //The application of the development, run by: nw .nwjs/app
45
+ * const stage = await stageNwjsApp({outdir: '.nwjs/app'})
46
+ * console.log(stage.directory, stage.release.version, stage.name)
47
+ */
48
+ export async function stageNwjsApp(options) {
49
+ const project = path.resolve(options.project ?? process.cwd());
50
+ const manifestFile = path.join(project, 'package.json');
51
+ if (!existsSync(manifestFile))
52
+ throw new Error(`${project} has no package.json`);
53
+ const manifest = JSON.parse(await readFile(manifestFile, 'utf8'));
54
+ const config = options.version ? { ...manifest.lakutata?.nwjs, version: options.version } : nwjsConfig(manifest);
55
+ const release = await nwjsRelease(config.version);
56
+ //nwjs.json, what the user interface is built for (its Chromium), follows the version of the application
57
+ const derived = `${JSON.stringify({ version: release.version, node: release.node, chromium: release.chromium }, null, 2)}\n`;
58
+ const derivedFile = path.join(project, 'nwjs.json');
59
+ if (!existsSync(derivedFile) || await readFile(derivedFile, 'utf8') !== derived)
60
+ await writeFile(derivedFile, derived);
61
+ const directory = path.resolve(project, options.outdir);
62
+ //The directory is made again: never the project or a directory holding it
63
+ if (!path.relative(directory, project).startsWith('..'))
64
+ throw new Error(`The application of NW.js is made in a directory of its own, not ${directory}`);
65
+ await rm(directory, { recursive: true, force: true });
66
+ await mkdir(directory, { recursive: true });
67
+ const bundle = await bundleProject({
68
+ project: project,
69
+ entry: options.entry,
70
+ outfile: path.join(directory, 'app.cjs'),
71
+ node: release.node,
72
+ minify: options.minify ?? false,
73
+ external: options.external,
74
+ directories: { native: 'app.native', resources: 'resources' }
75
+ });
76
+ //Its addons loaded by the runtime: its architecture, its headers, its library of Node.js on Windows
77
+ const platform = nwjsPlatform(release, options.platform, options.arch);
78
+ const addons = bundle.native && bundle.nativeDirectory ? await prepareNwjsAddons(project, bundle.nativeDirectory, bundle.native.files, release, platform) : { renamed: [], rebuilt: [] };
79
+ const name = nwjsName(manifest, config);
80
+ const nwManifest = {
81
+ name: name,
82
+ productName: manifest.productName ?? manifest.name,
83
+ version: manifest.version ?? '0.0.0',
84
+ main: 'main.js',
85
+ //The pages of the user interface, held by the webviews of the windows (without Node.js), are the files of the application
86
+ webview: { partitions: [{ name: 'trusted', accessible_resources: ['<all_urls>'] }] },
87
+ ...(config.chromiumArgs ? { 'chromium-args': config.chromiumArgs } : {})
88
+ };
89
+ await writeFile(path.join(directory, 'package.json'), `${JSON.stringify(nwManifest, null, 2)}\n`);
90
+ await writeFile(path.join(directory, 'main.js'), BACKGROUND_SCRIPT);
91
+ return { directory: directory, release: release, name: name, platform: platform, bundle: bundle, addons: addons };
92
+ }