@lakutata/builder 3.1.3 → 3.1.6
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 +24 -1
- package/README.zh-CN.md +7 -1
- package/dist/esm/index.js +5 -0
- package/dist/esm/lib/Archive.js +3 -2
- package/dist/esm/lib/Bundle.js +2 -1
- package/dist/esm/lib/Directories.js +18 -0
- package/dist/esm/lib/Executable.js +27 -6
- package/dist/esm/lib/Installer.js +28 -14
- package/dist/esm/lib/NativeRuntime.js +27 -3
- package/dist/esm/lib/Processes.js +3 -2
- package/dist/esm/lib/Tools.js +98 -19
- package/dist/esm/lib/linux/Linux.js +60 -10
- package/dist/esm/lib/mac/Mac.js +39 -11
- package/dist/esm/lib/mobile/Addons.js +675 -0
- package/dist/esm/lib/mobile/Node.js +190 -0
- package/dist/esm/lib/mobile/Stage.js +180 -0
- package/dist/esm/lib/nwjs/Addons.js +310 -0
- package/dist/esm/lib/nwjs/Package.js +149 -0
- package/dist/esm/lib/nwjs/Runtime.js +188 -0
- package/dist/esm/lib/nwjs/Stage.js +92 -0
- package/dist/esm/lib/win/Windows.js +68 -45
- package/dist/types/index.d.ts +7 -0
- package/dist/types/lib/Bundle.d.ts +5 -0
- package/dist/types/lib/Directories.d.ts +8 -0
- package/dist/types/lib/Executable.d.ts +7 -0
- package/dist/types/lib/Installer.d.ts +37 -4
- package/dist/types/lib/Processes.d.ts +2 -1
- package/dist/types/lib/Tools.d.ts +47 -1
- package/dist/types/lib/linux/Linux.d.ts +2 -1
- package/dist/types/lib/mac/Mac.d.ts +1 -1
- package/dist/types/lib/mobile/Addons.d.ts +154 -0
- package/dist/types/lib/mobile/Node.d.ts +89 -0
- package/dist/types/lib/mobile/Stage.d.ts +111 -0
- package/dist/types/lib/nwjs/Addons.d.ts +69 -0
- package/dist/types/lib/nwjs/Package.d.ts +56 -0
- package/dist/types/lib/nwjs/Runtime.d.ts +120 -0
- package/dist/types/lib/nwjs/Stage.d.ts +104 -0
- package/dist/types/lib/win/Windows.d.ts +30 -1
- package/package.json +2 -2
|
@@ -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
|
+
}
|
|
@@ -12,8 +12,8 @@ export const WINDOWS_TARGETS = ['nsis', 'msi', 'zip'];
|
|
|
12
12
|
/**
|
|
13
13
|
* The architecture of the packages (the one of the executable)
|
|
14
14
|
*/
|
|
15
|
-
function packageArch() {
|
|
16
|
-
return
|
|
15
|
+
function packageArch(plan) {
|
|
16
|
+
return { arm64: 'arm64', ia32: 'x86' }[plan.arch] ?? 'x64';
|
|
17
17
|
}
|
|
18
18
|
/**
|
|
19
19
|
* A text of XML
|
|
@@ -164,8 +164,9 @@ function numericVersion(version) {
|
|
|
164
164
|
* @param stage the files it installs
|
|
165
165
|
* @param file
|
|
166
166
|
* @param scripts the scripts of the application (written with the mark of UTF-8, which Windows PowerShell reads them by)
|
|
167
|
+
* @internal
|
|
167
168
|
*/
|
|
168
|
-
function nsisScript(plan, stage, file, scripts) {
|
|
169
|
+
export function nsisScript(plan, stage, file, scripts) {
|
|
169
170
|
const uninstallKey = `Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\${plan.appId}`;
|
|
170
171
|
//A text given (its $ are not variables of NSIS), a path of NSIS (its variables: $INSTDIR)
|
|
171
172
|
const string = (value) => `"${value.replace(/\$/g, '$$$$').replace(/"/g, '$\\"')}"`;
|
|
@@ -187,15 +188,20 @@ function nsisScript(plan, stage, file, scripts) {
|
|
|
187
188
|
const macro = (name) => scripts.include ? [` !ifmacrodef ${name}`, ` !insertmacro ${name}`, ' !endif'] : [];
|
|
188
189
|
//The directory of the application, given to its scripts
|
|
189
190
|
const environment = ' System::Call \'Kernel32::SetEnvironmentVariable(t "LAKUTATA_INSTALL_DIR", t "$INSTDIR")i\'';
|
|
191
|
+
//A desktop application: shortcuts to its executable, no installation script (PowerShell) of the service and of the PATH
|
|
192
|
+
const desktop = plan.desktop;
|
|
193
|
+
const shortcuts = desktop ? [`$SMPROGRAMS\\${plan.productName}.lnk`, `$DESKTOP\\${plan.productName}.lnk`] : [];
|
|
194
|
+
//A 32-bit program (Windows 7 32-bit) in the programs of 32 bits, with the 32-bit registry
|
|
195
|
+
const wide = plan.arch !== 'ia32';
|
|
190
196
|
return [
|
|
191
197
|
'Unicode true',
|
|
192
198
|
'ManifestDPIAware true',
|
|
193
|
-
'!include "x64.nsh"',
|
|
199
|
+
...wide ? ['!include "x64.nsh"'] : [],
|
|
194
200
|
`Name ${string(plan.productName)}`,
|
|
195
201
|
`OutFile ${string(file)}`,
|
|
196
202
|
//The icon of the application
|
|
197
203
|
...plan.icon ? [`Icon ${string(plan.icon)}`, `UninstallIcon ${string(plan.icon)}`] : [],
|
|
198
|
-
`InstallDir ${variables(`$PROGRAMFILES64\\${plan.name}`)}`,
|
|
204
|
+
`InstallDir ${variables(`${wide ? '$PROGRAMFILES64' : '$PROGRAMFILES'}\\${plan.name}`)}`,
|
|
199
205
|
'RequestExecutionLevel admin',
|
|
200
206
|
'SetCompressor /SOLID lzma',
|
|
201
207
|
'ShowInstDetails show',
|
|
@@ -210,13 +216,11 @@ function nsisScript(plan, stage, file, scripts) {
|
|
|
210
216
|
'',
|
|
211
217
|
'; The 64-bit registry and system (the installer is a 32-bit program)',
|
|
212
218
|
'Function .onInit',
|
|
213
|
-
' SetRegView 64',
|
|
214
|
-
' ${DisableX64FSRedirection}',
|
|
219
|
+
...wide ? [' SetRegView 64', ' ${DisableX64FSRedirection}'] : [],
|
|
215
220
|
...macro('customInit'),
|
|
216
221
|
'FunctionEnd',
|
|
217
222
|
'Function un.onInit',
|
|
218
|
-
' SetRegView 64',
|
|
219
|
-
' ${DisableX64FSRedirection}',
|
|
223
|
+
...wide ? [' SetRegView 64', ' ${DisableX64FSRedirection}'] : [],
|
|
220
224
|
...macro('customUnInit'),
|
|
221
225
|
'FunctionEnd',
|
|
222
226
|
'',
|
|
@@ -225,32 +229,36 @@ function nsisScript(plan, stage, file, scripts) {
|
|
|
225
229
|
environment,
|
|
226
230
|
' ; An upgrade replaces the application installed',
|
|
227
231
|
' StrCpy $R9 "install"',
|
|
228
|
-
|
|
232
|
+
` IfFileExists ${variables(`$INSTDIR\\${desktop ? desktop.executable : 'installer.ps1'}`)} 0 +2`,
|
|
229
233
|
' StrCpy $R9 "upgrade"',
|
|
230
234
|
...hook('preinstall'),
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
+
...desktop ? [] : [
|
|
236
|
+
' ; The service of the version replaced is stopped: its files are replaced',
|
|
237
|
+
' IfFileExists "$INSTDIR\\installer.ps1" 0 +3',
|
|
238
|
+
` ${script('stop')}`,
|
|
239
|
+
' Pop $0'
|
|
240
|
+
],
|
|
235
241
|
' SetOutPath "$INSTDIR"',
|
|
236
242
|
` File /r ${string(`${stage}\\*.*`)}`,
|
|
243
|
+
...shortcuts.map((shortcut) => ` CreateShortCut ${variables(shortcut)} ${variables(`$INSTDIR\\${desktop.executable}`)}`),
|
|
237
244
|
' WriteUninstaller "$INSTDIR\\uninstall.exe"',
|
|
238
245
|
` WriteRegStr HKLM ${string(uninstallKey)} "DisplayName" ${string(plan.productName)}`,
|
|
239
246
|
` WriteRegStr HKLM ${string(uninstallKey)} "DisplayVersion" ${string(plan.version)}`,
|
|
240
247
|
` WriteRegStr HKLM ${string(uninstallKey)} "Publisher" ${string(plan.vendor ?? plan.maintainer)}`,
|
|
241
248
|
` WriteRegStr HKLM ${string(uninstallKey)} "InstallLocation" "$INSTDIR"`,
|
|
242
|
-
` WriteRegStr HKLM ${string(uninstallKey)} "DisplayIcon" ${variables(`$INSTDIR\\${plan.program}.exe`)}`,
|
|
249
|
+
` WriteRegStr HKLM ${string(uninstallKey)} "DisplayIcon" ${variables(`$INSTDIR\\${desktop ? desktop.executable : `${plan.program}.exe`}`)}`,
|
|
243
250
|
` WriteRegStr HKLM ${string(uninstallKey)} "UninstallString" '"$INSTDIR\\uninstall.exe"'`,
|
|
244
251
|
` WriteRegStr HKLM ${string(uninstallKey)} "QuietUninstallString" '"$INSTDIR\\uninstall.exe" /S'`,
|
|
245
252
|
` WriteRegDWORD HKLM ${string(uninstallKey)} "NoModify" 1`,
|
|
246
253
|
` WriteRegDWORD HKLM ${string(uninstallKey)} "NoRepair" 1`,
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
254
|
+
...desktop ? [] : [
|
|
255
|
+
` ${script('install')}`,
|
|
256
|
+
' Pop $0',
|
|
257
|
+
' StrCmp $0 "0" +2',
|
|
258
|
+
' Abort "The installation failed ($0)"'
|
|
259
|
+
],
|
|
251
260
|
...hook('postinstall'),
|
|
252
|
-
` ${script('start')}`,
|
|
253
|
-
' Pop $0',
|
|
261
|
+
...desktop ? [] : [` ${script('start')}`, ' Pop $0'],
|
|
254
262
|
...macro('customInstall'),
|
|
255
263
|
'SectionEnd',
|
|
256
264
|
'',
|
|
@@ -259,8 +267,7 @@ function nsisScript(plan, stage, file, scripts) {
|
|
|
259
267
|
environment,
|
|
260
268
|
' StrCpy $R9 "remove"',
|
|
261
269
|
...macro('customUnInstall'),
|
|
262
|
-
` ${script('uninstall')}`,
|
|
263
|
-
' Pop $0',
|
|
270
|
+
...desktop ? shortcuts.map((shortcut) => ` Delete ${variables(shortcut)}`) : [` ${script('uninstall')}`, ' Pop $0'],
|
|
264
271
|
...hook('preremove'),
|
|
265
272
|
' RMDir /r "$INSTDIR"',
|
|
266
273
|
` DeleteRegKey HKLM ${string(uninstallKey)}`,
|
|
@@ -341,9 +348,11 @@ function msiScripts(hooks) {
|
|
|
341
348
|
* @param stage the files it installs
|
|
342
349
|
* @param serviceDirectory the files of its service (WinSW and its configuration)
|
|
343
350
|
* @param environment the environment file
|
|
351
|
+
* @internal
|
|
344
352
|
*/
|
|
345
|
-
function wixSource(plan, stage, serviceDirectory, environment) {
|
|
353
|
+
export function wixSource(plan, stage, serviceDirectory, environment) {
|
|
346
354
|
const scripts = msiScripts(plan.scripts.msi?.hooks ?? {});
|
|
355
|
+
const desktop = plan.desktop;
|
|
347
356
|
const id = (prefix, value) => `${prefix}${createHash('sha1').update(value).digest('hex').slice(0, 30)}`;
|
|
348
357
|
const components = [];
|
|
349
358
|
const directory = (absolute, relative, depth) => {
|
|
@@ -379,20 +388,33 @@ function wixSource(plan, stage, serviceDirectory, environment) {
|
|
|
379
388
|
...plan.icon ? [` <Icon Id="ProductIcon.ico" SourceFile="${xml(plan.icon)}"/>`, ' <Property Id="ARPPRODUCTICON" Value="ProductIcon.ico"/>'] : [],
|
|
380
389
|
` <Property Id="ARPINSTALLLOCATION" Value="[INSTALLDIR]"/>`,
|
|
381
390
|
' <Directory Id="TARGETDIR" Name="SourceDir">',
|
|
382
|
-
|
|
391
|
+
` <Directory Id="${plan.arch === 'ia32' ? 'ProgramFilesFolder' : 'ProgramFiles64Folder'}">`,
|
|
383
392
|
` <Directory Id="INSTALLDIR" Name="${xml(plan.name)}">`,
|
|
384
393
|
...files,
|
|
385
394
|
' </Directory>',
|
|
386
395
|
' </Directory>',
|
|
387
|
-
' <Directory Id="
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
396
|
+
...desktop ? [' <Directory Id="ProgramMenuFolder"/>', ' <Directory Id="DesktopFolder"/>'] : [
|
|
397
|
+
' <Directory Id="CommonAppDataFolder">',
|
|
398
|
+
` <Directory Id="DATADIR" Name="${xml(plan.name)}">`,
|
|
399
|
+
' <Directory Id="LOGSDIR" Name="logs"/>',
|
|
400
|
+
' </Directory>',
|
|
401
|
+
' </Directory>'
|
|
402
|
+
],
|
|
392
403
|
' </Directory>',
|
|
393
|
-
//The data, the logs and the environment file are kept by the removals
|
|
394
|
-
|
|
395
|
-
|
|
404
|
+
//The data, the logs and the environment file are kept by the removals (a service, a program of the command line)
|
|
405
|
+
...desktop ? [] : [
|
|
406
|
+
` <Component Id="Data" Directory="DATADIR" Guid="${namedUuid(`${plan.appId}:data`)}" Permanent="yes" KeyPath="yes"><CreateFolder/></Component>`,
|
|
407
|
+
` <Component Id="Logs" Directory="LOGSDIR" Guid="${namedUuid(`${plan.appId}:logs`)}" Permanent="yes" KeyPath="yes"><CreateFolder/></Component>`
|
|
408
|
+
],
|
|
409
|
+
//The shortcuts of a desktop application, their key a value of the registry of the user installing (the ones of
|
|
410
|
+
//the menus and of the desktop must be of HKCU: ICE43, ICE57)
|
|
411
|
+
...desktop ? [
|
|
412
|
+
` <Component Id="Shortcuts" Directory="INSTALLDIR" Guid="${namedUuid(`${plan.appId}:shortcuts`)}">`,
|
|
413
|
+
` <Shortcut Id="ProgramMenuShortcut" Directory="ProgramMenuFolder" Name="${xml(plan.productName)}" Target="[INSTALLDIR]${xml(desktop.executable)}" WorkingDirectory="INSTALLDIR"/>`,
|
|
414
|
+
` <Shortcut Id="DesktopShortcut" Directory="DesktopFolder" Name="${xml(plan.productName)}" Target="[INSTALLDIR]${xml(desktop.executable)}" WorkingDirectory="INSTALLDIR"/>`,
|
|
415
|
+
` <RegistryValue Root="HKCU" Key="Software\\${xml(plan.appId)}" Name="Shortcuts" Type="integer" Value="1" KeyPath="yes"/>`,
|
|
416
|
+
' </Component>'
|
|
417
|
+
] : [],
|
|
396
418
|
...environment ? [` <Component Id="Environment" Directory="DATADIR" Guid="${namedUuid(`${plan.appId}:environment`)}" Permanent="yes" NeverOverwrite="yes"><File Id="EnvironmentFile" Name="${xml(`${plan.name}.env`)}" Source="${xml(environment)}" KeyPath="yes"/></Component>`] : [],
|
|
397
419
|
...plan.addToPath ? [` <Component Id="Path" Directory="INSTALLDIR" Guid="${namedUuid(`${plan.appId}:path`)}" KeyPath="yes"><Environment Id="Path" Name="PATH" Value="[INSTALLDIR]" Permanent="no" Part="last" Action="set" System="yes"/></Component>`] : [],
|
|
398
420
|
...service ? [
|
|
@@ -419,8 +441,7 @@ function wixSource(plan, stage, serviceDirectory, environment) {
|
|
|
419
441
|
] : [],
|
|
420
442
|
' <Feature Id="Application" Level="1">',
|
|
421
443
|
...components.map((component) => ` <ComponentRef Id="${component}"/>`),
|
|
422
|
-
' <ComponentRef Id="Data"/>',
|
|
423
|
-
' <ComponentRef Id="Logs"/>',
|
|
444
|
+
...desktop ? [' <ComponentRef Id="Shortcuts"/>'] : [' <ComponentRef Id="Data"/>', ' <ComponentRef Id="Logs"/>'],
|
|
424
445
|
...environment ? [' <ComponentRef Id="Environment"/>'] : [],
|
|
425
446
|
...plan.addToPath ? [' <ComponentRef Id="Path"/>'] : [],
|
|
426
447
|
...service ? [' <ComponentRef Id="Service"/>'] : [],
|
|
@@ -449,8 +470,9 @@ async function must(command, args, cwd, what) {
|
|
|
449
470
|
* @param targets
|
|
450
471
|
* @param work
|
|
451
472
|
* @param outdir
|
|
473
|
+
* @param progress Called with what is being downloaded (WinSW, NSIS, WiX)
|
|
452
474
|
*/
|
|
453
|
-
export async function buildWindowsPackages(plan, targets, work, outdir) {
|
|
475
|
+
export async function buildWindowsPackages(plan, targets, work, outdir, progress) {
|
|
454
476
|
await mkdir(work, { recursive: true });
|
|
455
477
|
const files = [];
|
|
456
478
|
const service = plan.service;
|
|
@@ -460,14 +482,14 @@ export async function buildWindowsPackages(plan, targets, work, outdir) {
|
|
|
460
482
|
await mkdir(serviceDirectory, { recursive: true });
|
|
461
483
|
let environment;
|
|
462
484
|
if (service) {
|
|
463
|
-
await copyFile(await ensureTool('winsw'), path.join(serviceDirectory, `${installPaths(plan).wrapper}.exe`));
|
|
485
|
+
await copyFile(await ensureTool('winsw', progress), path.join(serviceDirectory, `${installPaths(plan).wrapper}.exe`));
|
|
464
486
|
await writeFile(path.join(serviceDirectory, `${installPaths(plan).wrapper}.xml`), serviceConfiguration(plan, service));
|
|
465
487
|
environment = path.join(serviceDirectory, `${plan.name}.env`);
|
|
466
488
|
await writeFile(environment, environmentFile(service));
|
|
467
489
|
}
|
|
468
490
|
for (const target of targets) {
|
|
469
491
|
if (target === 'zip') {
|
|
470
|
-
const base = `${plan.name}-${plan.version}-win-${packageArch()}`;
|
|
492
|
+
const base = `${plan.name}-${plan.version}-win-${packageArch(plan)}`;
|
|
471
493
|
await rm(path.join(work, base), { recursive: true, force: true });
|
|
472
494
|
await cp(plan.directory, path.join(work, base), { recursive: true });
|
|
473
495
|
const file = path.join(outdir, `${base}.zip`);
|
|
@@ -485,8 +507,9 @@ export async function buildWindowsPackages(plan, targets, work, outdir) {
|
|
|
485
507
|
if (service)
|
|
486
508
|
for (const name of readdirSync(serviceDirectory).filter((name) => !name.endsWith('.env')))
|
|
487
509
|
await copyFile(path.join(serviceDirectory, name), path.join(stage, name));
|
|
488
|
-
//Windows PowerShell reads the scripts of UTF-8 by their mark
|
|
489
|
-
|
|
510
|
+
//Windows PowerShell reads the scripts of UTF-8 by their mark (a desktop application has none)
|
|
511
|
+
if (!plan.desktop)
|
|
512
|
+
await writeFile(path.join(stage, 'installer.ps1'), `\ufeff${installerScript(plan)}`);
|
|
490
513
|
//The scripts of the application, extracted by the installer when it runs them
|
|
491
514
|
const own = plan.scripts.nsis;
|
|
492
515
|
const hooks = {};
|
|
@@ -502,22 +525,22 @@ export async function buildWindowsPackages(plan, targets, work, outdir) {
|
|
|
502
525
|
include = path.join(directory, 'include.nsh');
|
|
503
526
|
await writeFile(include, own.include.content);
|
|
504
527
|
}
|
|
505
|
-
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch()}-setup.exe`);
|
|
528
|
+
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch(plan)}-setup.exe`);
|
|
506
529
|
await rm(file, { force: true });
|
|
507
530
|
const script = path.join(work, 'installer.nsi');
|
|
508
531
|
await writeFile(script, `\ufeff${nsisScript(plan, stage, file, { hooks: hooks, include: include })}`);
|
|
509
|
-
await must(await ensureTool('nsis'), ['/V2', '/INPUTCHARSET', 'UTF8', script], work, 'The installer of NSIS');
|
|
532
|
+
await must(await ensureTool('nsis', progress), ['/V2', '/INPUTCHARSET', 'UTF8', script], work, 'The installer of NSIS');
|
|
510
533
|
files.push({ target: target, file: file, size: (await stat(file)).size });
|
|
511
534
|
continue;
|
|
512
535
|
}
|
|
513
536
|
//msi: compiled by candle, linked by light
|
|
514
537
|
const source = path.join(work, 'package.wxs');
|
|
515
538
|
await writeFile(source, wixSource(plan, plan.directory, serviceDirectory, environment));
|
|
516
|
-
const candle = await ensureTool('wix');
|
|
539
|
+
const candle = await ensureTool('wix', progress);
|
|
517
540
|
const light = path.join(path.dirname(candle), 'light.exe');
|
|
518
|
-
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch()}.msi`);
|
|
541
|
+
const file = path.join(outdir, `${plan.name}-${plan.version}-${packageArch(plan)}.msi`);
|
|
519
542
|
await rm(file, { force: true });
|
|
520
|
-
await must(candle, ['-nologo', '-arch', packageArch(), '-ext', 'WixUtilExtension', '-out', path.join(work, 'package.wixobj'), source], work, 'The package of Windows Installer');
|
|
543
|
+
await must(candle, ['-nologo', '-arch', packageArch(plan), '-ext', 'WixUtilExtension', '-out', path.join(work, 'package.wixobj'), source], work, 'The package of Windows Installer');
|
|
521
544
|
await must(light, ['-nologo', '-ext', 'WixUtilExtension', '-spdb', '-out', file, path.join(work, 'package.wixobj')], work, 'The package of Windows Installer');
|
|
522
545
|
files.push({ target: target, file: file, size: (await stat(file)).size });
|
|
523
546
|
}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -11,3 +11,10 @@ export { INSTALLER_HOOKS, NATIVE_HOOKS, type InstallerHook, type InstallerScript
|
|
|
11
11
|
export { detectLibc } from './lib/Platform.js';
|
|
12
12
|
export { WINDOWS_TARGETS, type WindowsTarget } from './lib/win/Windows.js';
|
|
13
13
|
export { MAC_TARGETS, type MacTarget } from './lib/mac/Mac.js';
|
|
14
|
+
export { downloadNwjs, nwjsPlatform, nwjsRelease, nwjsReleases, type NwjsFlavor, type NwjsRelease, type NwjsRuntime, type NwjsRuntimeOptions } from './lib/nwjs/Runtime.js';
|
|
15
|
+
export { stageNwjsApp, type NwjsConfig, type NwjsStage, type NwjsStageOptions } from './lib/nwjs/Stage.js';
|
|
16
|
+
export type { NwjsAddons } from './lib/nwjs/Addons.js';
|
|
17
|
+
export { buildNwjsApp, type NwjsApp, type NwjsAppOptions } from './lib/nwjs/Package.js';
|
|
18
|
+
export { stageMobileApp, type MobileStage, type MobileStageOptions } from './lib/mobile/Stage.js';
|
|
19
|
+
export { downloadMobileNode, MOBILE_NODE_RELEASE, MOBILE_NODE_VERSION, type AndroidAbi, type MobileNodeDownloadOptions, type MobilePlatform } from './lib/mobile/Node.js';
|
|
20
|
+
export type { IosSdk, MobileAddons } from './lib/mobile/Addons.js';
|
|
@@ -32,6 +32,11 @@ export type BundleOptions = {
|
|
|
32
32
|
* The runtime running the bundle: node (by default), or bun (the executables of Bun, which bundle it again)
|
|
33
33
|
*/
|
|
34
34
|
runtime?: 'node' | 'bun';
|
|
35
|
+
/**
|
|
36
|
+
* The version of Node.js running the bundle ("18.10", the one of NW.js 0.70): the bundle is written in the syntax that
|
|
37
|
+
* version reads; the version running the build by default
|
|
38
|
+
*/
|
|
39
|
+
node?: string;
|
|
35
40
|
/**
|
|
36
41
|
* Whether the bundle is the one of an executable (buildExecutable): it runs the scripts of its tree it is started
|
|
37
42
|
* for, in both layouts, and on Node.js it loads the modules left out of it from next to the executable
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copy a directory into another one, its links kept as they are: cp -a on macOS and Linux (the copy of Node.js turns
|
|
3
|
+
* the relative links into absolute ones before Node.js 18.17 and 20.2: its option verbatimSymlinks), the copy of Node.js
|
|
4
|
+
* on Windows (its directories have no links)
|
|
5
|
+
* @param source
|
|
6
|
+
* @param target
|
|
7
|
+
*/
|
|
8
|
+
export declare function copyDirectory(source: string, target: string): Promise<void>;
|
|
@@ -11,6 +11,13 @@ export type ExecutableOptions = Omit<BundleOptions, 'outfile' | 'native' | 'dire
|
|
|
11
11
|
* installers, the images)
|
|
12
12
|
*/
|
|
13
13
|
layout?: 'file' | 'directory';
|
|
14
|
+
/**
|
|
15
|
+
* The node program embedded in the executable, which also makes its single executable application. Another Node.js
|
|
16
|
+
* than the one running the build (20.12, 21.7 or later, which have the assets of the single executable applications),
|
|
17
|
+
* so that an older Node.js can run the build; the bundle is written in the syntax of the node program. The one
|
|
18
|
+
* running the build by default.
|
|
19
|
+
*/
|
|
20
|
+
nodeProgram?: string;
|
|
14
21
|
};
|
|
15
22
|
export type ExecutableResult = {
|
|
16
23
|
name: string;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type NwjsApp } from './nwjs/Package.js';
|
|
1
2
|
import { type ExecutableResult } from './Executable.js';
|
|
2
3
|
import { type InstallerScripts, type NativeScripts, type TargetScripts } from './Scripts.js';
|
|
3
4
|
import { type LinuxTarget } from './linux/Linux.js';
|
|
@@ -63,9 +64,10 @@ export type InstallerConfig = {
|
|
|
63
64
|
vendor?: string;
|
|
64
65
|
/**
|
|
65
66
|
* The runtime of the executable: node (by default) or bun; electron for the Electron applications, whose installers
|
|
66
|
-
* are made by electron-builder
|
|
67
|
+
* are made by electron-builder; nwjs for the applications of NW.js (lakutata.nwjs: its version), installed as desktop
|
|
68
|
+
* applications (shortcuts, /Applications, desktop entries)
|
|
67
69
|
*/
|
|
68
|
-
runtime?: 'node' | 'bun' | 'electron';
|
|
70
|
+
runtime?: 'node' | 'bun' | 'electron' | 'nwjs';
|
|
69
71
|
/**
|
|
70
72
|
* The configuration of electron-builder of an Electron application, merged over the one made from lakutata.installer
|
|
71
73
|
*/
|
|
@@ -168,6 +170,19 @@ export type InstallerOptions = {
|
|
|
168
170
|
* The directory of the packages, dist/installer by default
|
|
169
171
|
*/
|
|
170
172
|
outdir?: string;
|
|
173
|
+
/**
|
|
174
|
+
* The node program embedded in the executable (nodeProgram of buildExecutable), the one running the build by default
|
|
175
|
+
*/
|
|
176
|
+
nodeProgram?: string;
|
|
177
|
+
/**
|
|
178
|
+
* The architecture of an application of NW.js (process.arch), the one of the machine by default: ia32 for the 32-bit
|
|
179
|
+
* systems of Windows (Windows 7)
|
|
180
|
+
*/
|
|
181
|
+
arch?: string;
|
|
182
|
+
/**
|
|
183
|
+
* Called with what is being downloaded: the runtime of NW.js, the tools making the installers
|
|
184
|
+
*/
|
|
185
|
+
progress?: (line: string) => void;
|
|
171
186
|
};
|
|
172
187
|
export type InstallerResult = {
|
|
173
188
|
name: string;
|
|
@@ -181,9 +196,13 @@ export type InstallerResult = {
|
|
|
181
196
|
size: number;
|
|
182
197
|
}[];
|
|
183
198
|
/**
|
|
184
|
-
* The executable they install
|
|
199
|
+
* The executable they install, undefined for the applications of NW.js
|
|
185
200
|
*/
|
|
186
|
-
executable
|
|
201
|
+
executable?: ExecutableResult;
|
|
202
|
+
/**
|
|
203
|
+
* The application of NW.js they install (runtime nwjs)
|
|
204
|
+
*/
|
|
205
|
+
nwjs?: NwjsApp;
|
|
187
206
|
warnings: string[];
|
|
188
207
|
};
|
|
189
208
|
/**
|
|
@@ -231,6 +250,20 @@ export type InstallerPlan = {
|
|
|
231
250
|
* (lakutata.icon), none without it
|
|
232
251
|
*/
|
|
233
252
|
icon?: string;
|
|
253
|
+
/**
|
|
254
|
+
* The architecture of the program (process.arch: x64, ia32, arm64), which names the packages and, on Windows, the
|
|
255
|
+
* directory of the programs it is installed into
|
|
256
|
+
*/
|
|
257
|
+
arch: string;
|
|
258
|
+
/**
|
|
259
|
+
* A desktop application (NW.js): its executable in the directory (<product>.exe, <product>.app, <program>), given
|
|
260
|
+
* shortcuts (Windows), a desktop entry and icons (Linux), installed into /Applications (macOS); without service and
|
|
261
|
+
* outside the PATH by default; its icon (a PNG image: lakutata.icon), which the icons of Linux are made of
|
|
262
|
+
*/
|
|
263
|
+
desktop?: {
|
|
264
|
+
executable: string;
|
|
265
|
+
icon?: string;
|
|
266
|
+
};
|
|
234
267
|
};
|
|
235
268
|
/**
|
|
236
269
|
* Make the installers of the application for the platform it is made on (the installers of the other platforms are
|
|
@@ -13,9 +13,10 @@ export declare function spawnCommand(command: string, args: string[], options: S
|
|
|
13
13
|
* @param command
|
|
14
14
|
* @param args
|
|
15
15
|
* @param cwd
|
|
16
|
+
* @param env its environment, the one of the process by default
|
|
16
17
|
* @return the exit code and the output
|
|
17
18
|
*/
|
|
18
|
-
export declare function runCommand(command: string, args: string[], cwd: string): Promise<{
|
|
19
|
+
export declare function runCommand(command: string, args: string[], cwd: string, env?: NodeJS.ProcessEnv): Promise<{
|
|
19
20
|
code: number;
|
|
20
21
|
output: string;
|
|
21
22
|
}>;
|
|
@@ -22,11 +22,57 @@ declare const TOOLS: Record<'nfpm' | 'winsw' | 'nsis' | 'wix', Tool>;
|
|
|
22
22
|
* The directory of the cache of lakutata (the one of its tool): LAKUTATA_CACHE_DIR, else ~/.cache/lakutata
|
|
23
23
|
*/
|
|
24
24
|
export declare function cacheDirectory(): string;
|
|
25
|
+
/**
|
|
26
|
+
* The options of a download
|
|
27
|
+
*/
|
|
28
|
+
type DownloadOptions = {
|
|
29
|
+
/**
|
|
30
|
+
* Told when the file is downloaded again: a line naming it, read after "Downloading "
|
|
31
|
+
*/
|
|
32
|
+
progress?: (line: string) => void;
|
|
33
|
+
/**
|
|
34
|
+
* The headers of the requests
|
|
35
|
+
*/
|
|
36
|
+
headers?: Record<string, string>;
|
|
37
|
+
/**
|
|
38
|
+
* The while (milliseconds) a connection has to receive the minimum in, else it is left for another one: 30 s by
|
|
39
|
+
* default
|
|
40
|
+
*/
|
|
41
|
+
interval?: number;
|
|
42
|
+
/**
|
|
43
|
+
* The bytes a connection has to receive in each interval: 100 KB by default
|
|
44
|
+
*/
|
|
45
|
+
minimum?: number;
|
|
46
|
+
/**
|
|
47
|
+
* The connections tried: 3 by default
|
|
48
|
+
*/
|
|
49
|
+
attempts?: number;
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Download a file, its sha256 computed while it is written. A connection receiving too little (one of the releases of
|
|
53
|
+
* GitHub can stay at some kilobytes a second while another one downloads the file at once) or broken is left for
|
|
54
|
+
* another one, which downloads the file again from its start
|
|
55
|
+
* @param url
|
|
56
|
+
* @param file
|
|
57
|
+
* @param options
|
|
58
|
+
*/
|
|
59
|
+
export declare function downloadFile(url: string, file: string, options?: DownloadOptions): Promise<string>;
|
|
60
|
+
/**
|
|
61
|
+
* Move a directory written aside into its place in the cache. The one already there is kept when it is complete (put
|
|
62
|
+
* there by another build running at the same time), and replaced when it is not: left by a build that was stopped, or
|
|
63
|
+
* emptied by a cleaning of the temporary files that removes the files and keeps the directories (macOS cleans its
|
|
64
|
+
* temporary directory so)
|
|
65
|
+
* @param temporary The directory written, removed by the caller.
|
|
66
|
+
* @param target Its place in the cache.
|
|
67
|
+
* @param complete Whether the directory in its place is complete.
|
|
68
|
+
*/
|
|
69
|
+
export declare function moveIntoCache(temporary: string, target: string, complete: () => boolean): Promise<void>;
|
|
25
70
|
/**
|
|
26
71
|
* A tool of the builder: the one given by its environment variable (LAKUTATA_NFPM, LAKUTATA_WINSW, LAKUTATA_NSIS:
|
|
27
72
|
* makensis.exe, LAKUTATA_WIX: candle.exe, next to light.exe), else the version of the builder, downloaded once into the
|
|
28
73
|
* cache and checked with its sha256
|
|
29
74
|
* @param name
|
|
75
|
+
* @param progress Called with what is being downloaded
|
|
30
76
|
*/
|
|
31
|
-
export declare function ensureTool(name: keyof typeof TOOLS): Promise<string>;
|
|
77
|
+
export declare function ensureTool(name: keyof typeof TOOLS, progress?: (line: string) => void): Promise<string>;
|
|
32
78
|
export {};
|
|
@@ -21,8 +21,9 @@ export declare function scriptAction(target: Exclude<LinuxTarget, 'tar.gz'>, hoo
|
|
|
21
21
|
* @param targets
|
|
22
22
|
* @param work
|
|
23
23
|
* @param outdir
|
|
24
|
+
* @param progress Called with what is being downloaded (nFPM)
|
|
24
25
|
*/
|
|
25
|
-
export declare function buildLinuxPackages(plan: InstallerPlan, targets: LinuxTarget[], work: string, outdir: string): Promise<{
|
|
26
|
+
export declare function buildLinuxPackages(plan: InstallerPlan, targets: LinuxTarget[], work: string, outdir: string, progress?: (line: string) => void): Promise<{
|
|
26
27
|
target: string;
|
|
27
28
|
file: string;
|
|
28
29
|
size: number;
|
|
@@ -2,7 +2,7 @@ import type { InstallerPlan } from '../Installer.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* The installers of macOS: the package of its installer, and the archive of the directory of the executable
|
|
4
4
|
*/
|
|
5
|
-
export declare const MAC_TARGETS: readonly ["pkg", "tar.gz"];
|
|
5
|
+
export declare const MAC_TARGETS: readonly ["pkg", "dmg", "tar.gz"];
|
|
6
6
|
export type MacTarget = typeof MAC_TARGETS[number];
|
|
7
7
|
/**
|
|
8
8
|
* Make the installers of macOS of an application: the package installed by its installer (pkgbuild, productbuild), the
|