craft-native 0.0.185 → 0.0.187
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/dist/cli.js +235 -114
- package/dist/index.cjs +178 -35
- package/dist/index.d.cts +4 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +272 -130
- package/dist/ios/src/index.js +8 -3
- package/dist/ios/templates/CraftNativeScreen.swift +20 -6
- package/dist/temp-dir.d.ts +65 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -17,9 +17,8 @@ var __require = import.meta.require;
|
|
|
17
17
|
|
|
18
18
|
// src/index.ts
|
|
19
19
|
import { execFile as execFile2, spawn as spawn4 } from "child_process";
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import { join as join4 } from "path";
|
|
20
|
+
import { writeFileSync as writeFileSync4 } from "fs";
|
|
21
|
+
import { join as join5 } from "path";
|
|
23
22
|
import { promisify as promisify2 } from "util";
|
|
24
23
|
|
|
25
24
|
// src/binary-resolver.ts
|
|
@@ -58,11 +57,125 @@ function craftBinaryNotFoundMessage(triedPath) {
|
|
|
58
57
|
`);
|
|
59
58
|
}
|
|
60
59
|
// package.json
|
|
61
|
-
var version = "0.0.
|
|
60
|
+
var version = "0.0.187";
|
|
62
61
|
|
|
63
62
|
// src/sdk-version.ts
|
|
64
63
|
var SDK_VERSION = version;
|
|
65
64
|
|
|
65
|
+
// src/temp-dir.ts
|
|
66
|
+
import { existsSync as existsSync2, mkdtempSync, readdirSync, rmSync, statSync, writeFileSync } from "fs";
|
|
67
|
+
import { constants as osConstants, tmpdir } from "os";
|
|
68
|
+
import { join } from "path";
|
|
69
|
+
var OWNED_NAME = /^craft-(?:.+-)?p(\d+)-[A-Za-z0-9]{6}$/;
|
|
70
|
+
var KEEP_MARKER = ".craft-keep";
|
|
71
|
+
var SWEEP_MIN_AGE_MS = 60000;
|
|
72
|
+
var SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
|
|
73
|
+
var live = new Set;
|
|
74
|
+
var hooked = false;
|
|
75
|
+
var swept = false;
|
|
76
|
+
function removeQuietly(dir) {
|
|
77
|
+
try {
|
|
78
|
+
rmSync(dir, { recursive: true, force: true });
|
|
79
|
+
} catch {}
|
|
80
|
+
}
|
|
81
|
+
function removeAllTempDirs() {
|
|
82
|
+
for (const dir of live)
|
|
83
|
+
removeQuietly(dir);
|
|
84
|
+
live.clear();
|
|
85
|
+
unhook();
|
|
86
|
+
}
|
|
87
|
+
function onExit() {
|
|
88
|
+
for (const dir of live)
|
|
89
|
+
removeQuietly(dir);
|
|
90
|
+
live.clear();
|
|
91
|
+
}
|
|
92
|
+
function onSignal(signal) {
|
|
93
|
+
removeAllTempDirs();
|
|
94
|
+
if (process.listenerCount(signal) === 0)
|
|
95
|
+
process.exit(128 + (osConstants.signals[signal] ?? 1));
|
|
96
|
+
}
|
|
97
|
+
var signalHandlers = new Map(SIGNALS.map((signal) => [signal, () => onSignal(signal)]));
|
|
98
|
+
function hook() {
|
|
99
|
+
if (hooked)
|
|
100
|
+
return;
|
|
101
|
+
hooked = true;
|
|
102
|
+
process.on("exit", onExit);
|
|
103
|
+
for (const [signal, handler] of signalHandlers) {
|
|
104
|
+
try {
|
|
105
|
+
process.on(signal, handler);
|
|
106
|
+
} catch {}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function unhook() {
|
|
110
|
+
if (!hooked)
|
|
111
|
+
return;
|
|
112
|
+
hooked = false;
|
|
113
|
+
process.off("exit", onExit);
|
|
114
|
+
for (const [signal, handler] of signalHandlers)
|
|
115
|
+
process.off(signal, handler);
|
|
116
|
+
}
|
|
117
|
+
function pidIsAlive(pid) {
|
|
118
|
+
try {
|
|
119
|
+
process.kill(pid, 0);
|
|
120
|
+
return true;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return error.code === "EPERM";
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function sweepOrphanedTempDirs(options = {}) {
|
|
126
|
+
const root = options.root ?? tmpdir();
|
|
127
|
+
const isAlive = options.isAlive ?? pidIsAlive;
|
|
128
|
+
const minAge = options.minAgeMs ?? SWEEP_MIN_AGE_MS;
|
|
129
|
+
const now = options.now ?? Date.now();
|
|
130
|
+
const removed = [];
|
|
131
|
+
let names;
|
|
132
|
+
try {
|
|
133
|
+
names = readdirSync(root);
|
|
134
|
+
} catch {
|
|
135
|
+
return removed;
|
|
136
|
+
}
|
|
137
|
+
for (const name of names) {
|
|
138
|
+
const match = OWNED_NAME.exec(name);
|
|
139
|
+
if (!match)
|
|
140
|
+
continue;
|
|
141
|
+
const pid = Number(match[1]);
|
|
142
|
+
if (pid === process.pid || isAlive(pid))
|
|
143
|
+
continue;
|
|
144
|
+
const path = join(root, name);
|
|
145
|
+
try {
|
|
146
|
+
if (now - statSync(path).mtimeMs < minAge)
|
|
147
|
+
continue;
|
|
148
|
+
if (existsSync2(join(path, KEEP_MARKER)))
|
|
149
|
+
continue;
|
|
150
|
+
} catch {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
removeQuietly(path);
|
|
154
|
+
removed.push(path);
|
|
155
|
+
}
|
|
156
|
+
return removed;
|
|
157
|
+
}
|
|
158
|
+
function tempDirPrefix(label) {
|
|
159
|
+
const bare = label.replace(/^craft-/, "").replace(/-+$/, "");
|
|
160
|
+
return bare ? `craft-${bare}-p${process.pid}-` : `craft-p${process.pid}-`;
|
|
161
|
+
}
|
|
162
|
+
function createTempDir(label, root = tmpdir()) {
|
|
163
|
+
if (!swept) {
|
|
164
|
+
swept = true;
|
|
165
|
+
sweepOrphanedTempDirs({ root });
|
|
166
|
+
}
|
|
167
|
+
hook();
|
|
168
|
+
const dir = mkdtempSync(join(root, tempDirPrefix(label)));
|
|
169
|
+
live.add(dir);
|
|
170
|
+
return dir;
|
|
171
|
+
}
|
|
172
|
+
function removeTempDir(dir) {
|
|
173
|
+
removeQuietly(dir);
|
|
174
|
+
live.delete(dir);
|
|
175
|
+
if (live.size === 0)
|
|
176
|
+
unhook();
|
|
177
|
+
}
|
|
178
|
+
|
|
66
179
|
// src/package.ts
|
|
67
180
|
import { spawn } from "child_process";
|
|
68
181
|
import { createHash } from "crypto";
|
|
@@ -70,17 +183,16 @@ import {
|
|
|
70
183
|
chmodSync,
|
|
71
184
|
copyFileSync,
|
|
72
185
|
cpSync,
|
|
73
|
-
existsSync as
|
|
186
|
+
existsSync as existsSync3,
|
|
74
187
|
lstatSync,
|
|
75
188
|
mkdirSync,
|
|
76
|
-
mkdtempSync,
|
|
77
189
|
readFileSync,
|
|
78
|
-
readdirSync,
|
|
79
|
-
rmSync,
|
|
80
|
-
writeFileSync
|
|
190
|
+
readdirSync as readdirSync2,
|
|
191
|
+
rmSync as rmSync2,
|
|
192
|
+
writeFileSync as writeFileSync2
|
|
81
193
|
} from "fs";
|
|
82
|
-
import { homedir
|
|
83
|
-
import { basename, join } from "path";
|
|
194
|
+
import { homedir } from "os";
|
|
195
|
+
import { basename, join as join2 } from "path";
|
|
84
196
|
import { deflateRawSync } from "zlib";
|
|
85
197
|
var DEFAULT_DEB_DEPENDENCIES = ["libgtk-3-0", "libwebkit2gtk-4.1-37", "libnotify-bin"];
|
|
86
198
|
var CRC32_TABLE = (() => {
|
|
@@ -165,12 +277,12 @@ function formatPackagingCommandError(tool, code, stdout, stderr) {
|
|
|
165
277
|
}
|
|
166
278
|
async function packageApp(config) {
|
|
167
279
|
const results = [];
|
|
168
|
-
if (!config.binaryPath || !
|
|
280
|
+
if (!config.binaryPath || !existsSync3(config.binaryPath)) {
|
|
169
281
|
throw new Error(`Binary not found: ${config.binaryPath}`);
|
|
170
282
|
}
|
|
171
283
|
const platforms = config.platforms || [detectPlatform()];
|
|
172
|
-
const outDir = config.outDir ||
|
|
173
|
-
if (!
|
|
284
|
+
const outDir = config.outDir || join2(process.cwd(), "dist");
|
|
285
|
+
if (!existsSync3(outDir)) {
|
|
174
286
|
mkdirSync(outDir, { recursive: true });
|
|
175
287
|
}
|
|
176
288
|
for (const platform of platforms) {
|
|
@@ -193,7 +305,7 @@ async function packageMacOS(config, outDir) {
|
|
|
193
305
|
const { name, version: version2, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
|
|
194
306
|
const opts = config.macos || {};
|
|
195
307
|
const hardenedRuntime = !opts.appStore;
|
|
196
|
-
const appBundlePath =
|
|
308
|
+
const appBundlePath = join2(outDir, `${name}.app`);
|
|
197
309
|
const appBundle = createMacOSAppBundle({
|
|
198
310
|
name,
|
|
199
311
|
version: version2,
|
|
@@ -240,7 +352,7 @@ async function packageMacOS(config, outDir) {
|
|
|
240
352
|
}
|
|
241
353
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
242
354
|
if (opts.dmg !== false) {
|
|
243
|
-
const outputPath =
|
|
355
|
+
const outputPath = join2(outDir, `${name}-${version2}.dmg`);
|
|
244
356
|
const dmgResult = await createDMG({ appBundlePath, outputPath, volumeName: name });
|
|
245
357
|
results.push({
|
|
246
358
|
success: dmgResult.success,
|
|
@@ -253,7 +365,7 @@ async function packageMacOS(config, outDir) {
|
|
|
253
365
|
results.push(...await notarizeIfRequested(opts, outputPath, "dmg"));
|
|
254
366
|
}
|
|
255
367
|
if (opts.pkg || opts.appStore) {
|
|
256
|
-
const outputPath =
|
|
368
|
+
const outputPath = join2(outDir, `${name}-${version2}.pkg`);
|
|
257
369
|
const pkgResult = await createPKG({
|
|
258
370
|
appBundlePath,
|
|
259
371
|
outputPath,
|
|
@@ -311,7 +423,7 @@ async function packageWindows(config, outDir) {
|
|
|
311
423
|
name,
|
|
312
424
|
version: version2,
|
|
313
425
|
binaryPath: config.binaryPath,
|
|
314
|
-
outputPath:
|
|
426
|
+
outputPath: join2(outDir, `${name}-${version2}.msi`),
|
|
315
427
|
manufacturer: config.author || "Unknown",
|
|
316
428
|
architecture: opts.architecture || windowsArchitecture(process.arch),
|
|
317
429
|
additionalFiles: opts.additionalFiles,
|
|
@@ -335,7 +447,7 @@ async function packageWindows(config, outDir) {
|
|
|
335
447
|
manufacturer: config.author || "Unknown",
|
|
336
448
|
binaryPath: config.binaryPath,
|
|
337
449
|
additionalFiles: opts.additionalFiles,
|
|
338
|
-
outputPath:
|
|
450
|
+
outputPath: join2(outDir, `${name}-${version2}-windows.zip`)
|
|
339
451
|
});
|
|
340
452
|
results.push({
|
|
341
453
|
success: zipResult.success,
|
|
@@ -356,7 +468,7 @@ async function packageLinux(config, outDir) {
|
|
|
356
468
|
name,
|
|
357
469
|
version: version2,
|
|
358
470
|
binaryPath: config.binaryPath,
|
|
359
|
-
outputPath:
|
|
471
|
+
outputPath: join2(outDir, `${name}_${version2}_amd64.deb`),
|
|
360
472
|
description: config.description || "",
|
|
361
473
|
maintainer: config.author || "Unknown",
|
|
362
474
|
dependencies: opts.debDependencies || [...DEFAULT_DEB_DEPENDENCIES],
|
|
@@ -376,7 +488,7 @@ async function packageLinux(config, outDir) {
|
|
|
376
488
|
name,
|
|
377
489
|
version: version2,
|
|
378
490
|
binaryPath: config.binaryPath,
|
|
379
|
-
outputPath:
|
|
491
|
+
outputPath: join2(outDir, `${name}-${version2}-1.x86_64.rpm`),
|
|
380
492
|
description: config.description || "",
|
|
381
493
|
requires: opts.rpmDependencies || ["gtk3", "webkit2gtk3"]
|
|
382
494
|
});
|
|
@@ -393,7 +505,7 @@ async function packageLinux(config, outDir) {
|
|
|
393
505
|
name,
|
|
394
506
|
version: version2,
|
|
395
507
|
binaryPath: config.binaryPath,
|
|
396
|
-
outputPath:
|
|
508
|
+
outputPath: join2(outDir, `${name}-${version2}-x86_64.AppImage`),
|
|
397
509
|
iconPath: config.iconPath
|
|
398
510
|
});
|
|
399
511
|
results.push({
|
|
@@ -538,32 +650,32 @@ function notarytoolArguments(opts) {
|
|
|
538
650
|
function createMacOSAppBundle(opts) {
|
|
539
651
|
try {
|
|
540
652
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
541
|
-
const contents =
|
|
542
|
-
const macOS =
|
|
653
|
+
const contents = join2(outputPath, "Contents");
|
|
654
|
+
const macOS = join2(contents, "MacOS");
|
|
543
655
|
mkdirSync(macOS, { recursive: true });
|
|
544
|
-
mkdirSync(
|
|
545
|
-
copyFileSync(binaryPath,
|
|
546
|
-
chmodSync(
|
|
656
|
+
mkdirSync(join2(contents, "Resources"), { recursive: true });
|
|
657
|
+
copyFileSync(binaryPath, join2(macOS, name));
|
|
658
|
+
chmodSync(join2(macOS, name), 493);
|
|
547
659
|
for (const executable of additionalExecutables || []) {
|
|
548
|
-
if (!
|
|
660
|
+
if (!existsSync3(executable))
|
|
549
661
|
return { success: false, error: `Additional executable not found: ${executable}` };
|
|
550
|
-
const destination =
|
|
662
|
+
const destination = join2(macOS, basename(executable));
|
|
551
663
|
copyFileSync(executable, destination);
|
|
552
664
|
chmodSync(destination, 493);
|
|
553
665
|
}
|
|
554
666
|
let iconName;
|
|
555
667
|
if (iconPath) {
|
|
556
|
-
if (!
|
|
668
|
+
if (!existsSync3(iconPath))
|
|
557
669
|
return { success: false, error: `Icon not found: ${iconPath}` };
|
|
558
670
|
iconName = basename(iconPath).replace(/\.icns$/i, "");
|
|
559
|
-
copyFileSync(iconPath,
|
|
671
|
+
copyFileSync(iconPath, join2(contents, "Resources", `${iconName}.icns`));
|
|
560
672
|
}
|
|
561
673
|
if (provisioningProfile) {
|
|
562
|
-
if (!
|
|
674
|
+
if (!existsSync3(provisioningProfile))
|
|
563
675
|
return { success: false, error: `Provisioning profile not found: ${provisioningProfile}` };
|
|
564
|
-
copyFileSync(provisioningProfile,
|
|
676
|
+
copyFileSync(provisioningProfile, join2(contents, "embedded.provisionprofile"));
|
|
565
677
|
}
|
|
566
|
-
|
|
678
|
+
writeFileSync2(join2(contents, "Info.plist"), macOSInfoPlist({ ...opts, iconName }));
|
|
567
679
|
return { success: true };
|
|
568
680
|
} catch (error) {
|
|
569
681
|
return { success: false, error: error.message };
|
|
@@ -574,7 +686,7 @@ function pathContentBytes(path) {
|
|
|
574
686
|
const stat = lstatSync(path);
|
|
575
687
|
if (!stat.isDirectory())
|
|
576
688
|
return stat.size;
|
|
577
|
-
return
|
|
689
|
+
return readdirSync2(path).reduce((total, entry) => total + pathContentBytes(join2(path, entry)), 0);
|
|
578
690
|
}
|
|
579
691
|
function dmgCapacityMegabytes(contentBytes) {
|
|
580
692
|
if (!Number.isSafeInteger(contentBytes) || contentBytes < 0)
|
|
@@ -637,7 +749,7 @@ async function createDMG(opts) {
|
|
|
637
749
|
if (!shouldRetryHdiutil(result.error, attempt))
|
|
638
750
|
return { success: false, error: failures.join(`
|
|
639
751
|
`) };
|
|
640
|
-
|
|
752
|
+
rmSync2(opts.outputPath, { force: true });
|
|
641
753
|
await new Promise((resolve) => setTimeout(resolve, attempt * 2000));
|
|
642
754
|
}
|
|
643
755
|
return { success: false, error: failures.join(`
|
|
@@ -695,16 +807,16 @@ async function createPKG(opts) {
|
|
|
695
807
|
}));
|
|
696
808
|
return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
|
|
697
809
|
}
|
|
698
|
-
const tempDir =
|
|
810
|
+
const tempDir = createTempDir("craft-pkg-");
|
|
699
811
|
try {
|
|
700
|
-
const root =
|
|
701
|
-
const appsDir =
|
|
812
|
+
const root = join2(tempDir, "root");
|
|
813
|
+
const appsDir = join2(root, "Applications");
|
|
702
814
|
mkdirSync(appsDir, { recursive: true, mode: 493 });
|
|
703
815
|
chmodSync(root, 493);
|
|
704
816
|
const bundleName = basename(opts.appBundlePath);
|
|
705
|
-
cpSync(opts.appBundlePath,
|
|
706
|
-
const componentPlistPath =
|
|
707
|
-
|
|
817
|
+
cpSync(opts.appBundlePath, join2(appsDir, bundleName), { recursive: true });
|
|
818
|
+
const componentPlistPath = join2(tempDir, "component.plist");
|
|
819
|
+
writeFileSync2(componentPlistPath, pkgbuildComponentPlist(`Applications/${bundleName}`));
|
|
708
820
|
const built = await runTool("pkgbuild", pkgbuildArguments({
|
|
709
821
|
root,
|
|
710
822
|
componentPlistPath,
|
|
@@ -715,7 +827,7 @@ async function createPKG(opts) {
|
|
|
715
827
|
}));
|
|
716
828
|
return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
|
|
717
829
|
} finally {
|
|
718
|
-
|
|
830
|
+
removeTempDir(tempDir);
|
|
719
831
|
}
|
|
720
832
|
}
|
|
721
833
|
function xml(value) {
|
|
@@ -812,7 +924,7 @@ function windowsCompanionFiles(paths, executableName) {
|
|
|
812
924
|
if (seen.has(name.toLowerCase()))
|
|
813
925
|
throw new Error(`Duplicate Windows package file: ${name}`);
|
|
814
926
|
seen.add(name.toLowerCase());
|
|
815
|
-
if (!
|
|
927
|
+
if (!existsSync3(path) || lstatSync(path).isDirectory())
|
|
816
928
|
throw new Error(`Windows companion file not found: ${path}`);
|
|
817
929
|
return { path, name };
|
|
818
930
|
});
|
|
@@ -835,18 +947,18 @@ function runCommand(command, args, cwd) {
|
|
|
835
947
|
});
|
|
836
948
|
}
|
|
837
949
|
async function createMSI(opts) {
|
|
838
|
-
const tempDir =
|
|
950
|
+
const tempDir = createTempDir("craft-msi-");
|
|
839
951
|
try {
|
|
840
952
|
const binaryName = windowsExecutableName(opts.name);
|
|
841
953
|
const additionalFiles = windowsCompanionFiles(opts.additionalFiles, binaryName);
|
|
842
|
-
const sourcePath =
|
|
843
|
-
const wxsPath =
|
|
844
|
-
const wixobjPath =
|
|
954
|
+
const sourcePath = join2(tempDir, binaryName);
|
|
955
|
+
const wxsPath = join2(tempDir, "installer.wxs");
|
|
956
|
+
const wixobjPath = join2(tempDir, "installer.wixobj");
|
|
845
957
|
copyFileSync(opts.binaryPath, sourcePath);
|
|
846
|
-
|
|
958
|
+
writeFileSync2(join2(tempDir, WINDOWS_NOTIFICATION_ID_FILE), windowsNotificationAppId(opts.name, opts.manufacturer));
|
|
847
959
|
for (const file of additionalFiles)
|
|
848
|
-
copyFileSync(file.path,
|
|
849
|
-
|
|
960
|
+
copyFileSync(file.path, join2(tempDir, file.name));
|
|
961
|
+
writeFileSync2(wxsPath, renderWixSource(opts, binaryName, additionalFiles.map((file) => file.name)));
|
|
850
962
|
await runCommand("candle.exe", candleArguments(opts.architecture, wixobjPath, wxsPath), tempDir);
|
|
851
963
|
await runCommand("light.exe", ["-nologo", "-sval", "-out", opts.outputPath, wixobjPath], tempDir);
|
|
852
964
|
if (opts.certificatePath) {
|
|
@@ -863,7 +975,7 @@ async function createMSI(opts) {
|
|
|
863
975
|
const missingTool = /ENOENT|not found/i.test(message);
|
|
864
976
|
return { success: false, error: missingTool ? `WiX Toolset not found: ${message}` : message };
|
|
865
977
|
} finally {
|
|
866
|
-
|
|
978
|
+
removeTempDir(tempDir);
|
|
867
979
|
}
|
|
868
980
|
}
|
|
869
981
|
async function createZIP(opts) {
|
|
@@ -875,7 +987,7 @@ async function createZIP(opts) {
|
|
|
875
987
|
for (const file of additionalFiles)
|
|
876
988
|
entries.push({ name: file.name, data: new Uint8Array(readFileSync(file.path)) });
|
|
877
989
|
const zip = buildZip(entries);
|
|
878
|
-
|
|
990
|
+
writeFileSync2(opts.outputPath, zip);
|
|
879
991
|
return { success: true, outputPath: opts.outputPath };
|
|
880
992
|
} catch (err) {
|
|
881
993
|
return { success: false, error: `Failed to write ZIP: ${err.message}` };
|
|
@@ -883,6 +995,7 @@ async function createZIP(opts) {
|
|
|
883
995
|
}
|
|
884
996
|
async function createDEB(opts) {
|
|
885
997
|
return new Promise((resolve) => {
|
|
998
|
+
let staging;
|
|
886
999
|
try {
|
|
887
1000
|
const sanitizedName = opts.name.toLowerCase();
|
|
888
1001
|
const safeDebName = /^[a-z0-9._+-]+$/;
|
|
@@ -905,16 +1018,17 @@ async function createDEB(opts) {
|
|
|
905
1018
|
}
|
|
906
1019
|
}
|
|
907
1020
|
const desktopContent = linuxDesktopEntry(opts.name, sanitizedName, opts.urlSchemes, opts.launchUrl);
|
|
908
|
-
const tempDir =
|
|
909
|
-
|
|
910
|
-
const
|
|
911
|
-
const
|
|
1021
|
+
const tempDir = createTempDir("craft-deb-");
|
|
1022
|
+
staging = tempDir;
|
|
1023
|
+
const debianDir = join2(tempDir, "DEBIAN");
|
|
1024
|
+
const binDir = join2(tempDir, "usr", "bin");
|
|
1025
|
+
const applicationsDir = join2(tempDir, "usr", "share", "applications");
|
|
912
1026
|
mkdirSync(debianDir, { recursive: true });
|
|
913
1027
|
mkdirSync(binDir, { recursive: true });
|
|
914
1028
|
mkdirSync(applicationsDir, { recursive: true });
|
|
915
1029
|
const binaryName = sanitizedName;
|
|
916
|
-
copyFileSync(opts.binaryPath,
|
|
917
|
-
chmodSync(
|
|
1030
|
+
copyFileSync(opts.binaryPath, join2(binDir, binaryName));
|
|
1031
|
+
chmodSync(join2(binDir, binaryName), 493);
|
|
918
1032
|
const controlContent = `Package: ${sanitizedName}
|
|
919
1033
|
Version: ${opts.version}
|
|
920
1034
|
Section: utils
|
|
@@ -924,11 +1038,11 @@ Depends: ${opts.dependencies.join(", ")}
|
|
|
924
1038
|
Maintainer: ${maintainer}
|
|
925
1039
|
Description: ${description || opts.name}
|
|
926
1040
|
`;
|
|
927
|
-
|
|
928
|
-
|
|
1041
|
+
writeFileSync2(join2(debianDir, "control"), controlContent);
|
|
1042
|
+
writeFileSync2(join2(applicationsDir, `${binaryName}.desktop`), desktopContent);
|
|
929
1043
|
const proc = spawn("dpkg-deb", ["--build", tempDir, opts.outputPath]);
|
|
930
1044
|
proc.on("close", (code) => {
|
|
931
|
-
|
|
1045
|
+
removeTempDir(tempDir);
|
|
932
1046
|
if (code === 0) {
|
|
933
1047
|
resolve({ success: true, outputPath: opts.outputPath });
|
|
934
1048
|
} else {
|
|
@@ -936,10 +1050,12 @@ Description: ${description || opts.name}
|
|
|
936
1050
|
}
|
|
937
1051
|
});
|
|
938
1052
|
proc.on("error", (err) => {
|
|
939
|
-
|
|
1053
|
+
removeTempDir(tempDir);
|
|
940
1054
|
resolve({ success: false, error: err.message });
|
|
941
1055
|
});
|
|
942
1056
|
} catch (error) {
|
|
1057
|
+
if (staging)
|
|
1058
|
+
removeTempDir(staging);
|
|
943
1059
|
resolve({ success: false, error: error.message });
|
|
944
1060
|
}
|
|
945
1061
|
});
|
|
@@ -947,11 +1063,11 @@ Description: ${description || opts.name}
|
|
|
947
1063
|
async function createRPM(opts) {
|
|
948
1064
|
return new Promise((resolve) => {
|
|
949
1065
|
try {
|
|
950
|
-
const buildRoot =
|
|
951
|
-
const specDir =
|
|
952
|
-
const sourcesDir =
|
|
953
|
-
const buildDir =
|
|
954
|
-
const rpmsDir =
|
|
1066
|
+
const buildRoot = join2(homedir(), "rpmbuild");
|
|
1067
|
+
const specDir = join2(buildRoot, "SPECS");
|
|
1068
|
+
const sourcesDir = join2(buildRoot, "SOURCES");
|
|
1069
|
+
const buildDir = join2(buildRoot, "BUILD");
|
|
1070
|
+
const rpmsDir = join2(buildRoot, "RPMS");
|
|
955
1071
|
mkdirSync(specDir, { recursive: true });
|
|
956
1072
|
mkdirSync(sourcesDir, { recursive: true });
|
|
957
1073
|
mkdirSync(buildDir, { recursive: true });
|
|
@@ -975,7 +1091,7 @@ async function createRPM(opts) {
|
|
|
975
1091
|
}
|
|
976
1092
|
return r;
|
|
977
1093
|
}).join(", ");
|
|
978
|
-
copyFileSync(opts.binaryPath,
|
|
1094
|
+
copyFileSync(opts.binaryPath, join2(sourcesDir, sanitizedName));
|
|
979
1095
|
const specContent = `Name: ${sanitizedName}
|
|
980
1096
|
Version: ${opts.version}
|
|
981
1097
|
Release: 1%{?dist}
|
|
@@ -993,13 +1109,13 @@ install -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}
|
|
|
993
1109
|
%files
|
|
994
1110
|
/usr/bin/${sanitizedName}
|
|
995
1111
|
`;
|
|
996
|
-
const specPath =
|
|
997
|
-
|
|
1112
|
+
const specPath = join2(specDir, `${opts.name.toLowerCase()}.spec`);
|
|
1113
|
+
writeFileSync2(specPath, specContent);
|
|
998
1114
|
const proc = spawn("rpmbuild", ["-bb", specPath]);
|
|
999
1115
|
proc.on("close", (code) => {
|
|
1000
1116
|
if (code === 0) {
|
|
1001
1117
|
const rpmName = `${opts.name.toLowerCase()}-${opts.version}-1.x86_64.rpm`;
|
|
1002
|
-
const builtRpmPath =
|
|
1118
|
+
const builtRpmPath = join2(rpmsDir, "x86_64", rpmName);
|
|
1003
1119
|
try {
|
|
1004
1120
|
copyFileSync(builtRpmPath, opts.outputPath);
|
|
1005
1121
|
resolve({ success: true, outputPath: opts.outputPath });
|
|
@@ -1020,24 +1136,26 @@ install -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}
|
|
|
1020
1136
|
}
|
|
1021
1137
|
async function createAppImage(opts) {
|
|
1022
1138
|
return new Promise((resolve) => {
|
|
1139
|
+
let staging;
|
|
1023
1140
|
try {
|
|
1024
|
-
const appDir =
|
|
1025
|
-
|
|
1026
|
-
const
|
|
1027
|
-
const
|
|
1141
|
+
const appDir = createTempDir("craft-appimage-");
|
|
1142
|
+
staging = appDir;
|
|
1143
|
+
const appDirPath = join2(appDir, `${opts.name}.AppDir`);
|
|
1144
|
+
const binDir = join2(appDirPath, "usr", "bin");
|
|
1145
|
+
const shareDir = join2(appDirPath, "usr", "share");
|
|
1028
1146
|
mkdirSync(binDir, { recursive: true });
|
|
1029
1147
|
mkdirSync(shareDir, { recursive: true });
|
|
1030
1148
|
const binaryName = opts.name.toLowerCase();
|
|
1031
|
-
copyFileSync(opts.binaryPath,
|
|
1032
|
-
chmodSync(
|
|
1149
|
+
copyFileSync(opts.binaryPath, join2(binDir, binaryName));
|
|
1150
|
+
chmodSync(join2(binDir, binaryName), 493);
|
|
1033
1151
|
const appRunContent = `#!/bin/bash
|
|
1034
1152
|
SELF=$(readlink -f "$0")
|
|
1035
1153
|
HERE=\${SELF%/*}
|
|
1036
1154
|
export PATH="\${HERE}/usr/bin/:\${PATH}"
|
|
1037
1155
|
exec "\${HERE}/usr/bin/${binaryName}" "$@"
|
|
1038
1156
|
`;
|
|
1039
|
-
|
|
1040
|
-
chmodSync(
|
|
1157
|
+
writeFileSync2(join2(appDirPath, "AppRun"), appRunContent);
|
|
1158
|
+
chmodSync(join2(appDirPath, "AppRun"), 493);
|
|
1041
1159
|
const desktopContent = `[Desktop Entry]
|
|
1042
1160
|
Type=Application
|
|
1043
1161
|
Name=${opts.name}
|
|
@@ -1046,9 +1164,9 @@ Terminal=false
|
|
|
1046
1164
|
Categories=Utility;
|
|
1047
1165
|
Icon=${binaryName}
|
|
1048
1166
|
`;
|
|
1049
|
-
|
|
1050
|
-
if (opts.iconPath &&
|
|
1051
|
-
copyFileSync(opts.iconPath,
|
|
1167
|
+
writeFileSync2(join2(appDirPath, `${binaryName}.desktop`), desktopContent);
|
|
1168
|
+
if (opts.iconPath && existsSync3(opts.iconPath)) {
|
|
1169
|
+
copyFileSync(opts.iconPath, join2(appDirPath, `${binaryName}.png`));
|
|
1052
1170
|
} else {
|
|
1053
1171
|
const placeholderPng = Buffer.from([
|
|
1054
1172
|
137,
|
|
@@ -1121,13 +1239,13 @@ Icon=${binaryName}
|
|
|
1121
1239
|
96,
|
|
1122
1240
|
130
|
|
1123
1241
|
]);
|
|
1124
|
-
|
|
1242
|
+
writeFileSync2(join2(appDirPath, `${binaryName}.png`), placeholderPng);
|
|
1125
1243
|
}
|
|
1126
1244
|
const proc = spawn("appimagetool", [appDirPath, opts.outputPath], {
|
|
1127
1245
|
env: { ...process.env, ARCH: "x86_64" }
|
|
1128
1246
|
});
|
|
1129
1247
|
proc.on("close", (code) => {
|
|
1130
|
-
|
|
1248
|
+
removeTempDir(appDir);
|
|
1131
1249
|
if (code === 0) {
|
|
1132
1250
|
chmodSync(opts.outputPath, 493);
|
|
1133
1251
|
resolve({ success: true, outputPath: opts.outputPath });
|
|
@@ -1136,10 +1254,12 @@ Icon=${binaryName}
|
|
|
1136
1254
|
}
|
|
1137
1255
|
});
|
|
1138
1256
|
proc.on("error", (err) => {
|
|
1139
|
-
|
|
1257
|
+
removeTempDir(appDir);
|
|
1140
1258
|
resolve({ success: false, error: `appimagetool not found: ${err.message}` });
|
|
1141
1259
|
});
|
|
1142
1260
|
} catch (error) {
|
|
1261
|
+
if (staging)
|
|
1262
|
+
removeTempDir(staging);
|
|
1143
1263
|
resolve({ success: false, error: error.message });
|
|
1144
1264
|
}
|
|
1145
1265
|
});
|
|
@@ -9996,18 +10116,17 @@ __export(exports_updater, {
|
|
|
9996
10116
|
DeltaGenerator: () => DeltaGenerator,
|
|
9997
10117
|
AutoUpdater: () => AutoUpdater
|
|
9998
10118
|
});
|
|
9999
|
-
import { createReadStream, createWriteStream, existsSync as
|
|
10000
|
-
import { join as
|
|
10001
|
-
import { tmpdir as
|
|
10119
|
+
import { createReadStream, createWriteStream, existsSync as existsSync5, mkdirSync as mkdirSync2, readFileSync as readFileSync2, rmdirSync, statSync as statSync3, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
10120
|
+
import { join as join4, basename as basename3, dirname as dirname2 } from "path";
|
|
10121
|
+
import { tmpdir as tmpdir2 } from "os";
|
|
10002
10122
|
import { execFileSync as execFileSync2, spawn as spawn3 } from "child_process";
|
|
10003
10123
|
import { createHash as createHash2 } from "crypto";
|
|
10004
10124
|
import { EventEmitter as EventEmitter3 } from "events";
|
|
10005
10125
|
|
|
10006
10126
|
// src/updater/macos-bundle.ts
|
|
10007
10127
|
import { execFile, execFileSync } from "child_process";
|
|
10008
|
-
import { accessSync, constants, existsSync as
|
|
10009
|
-
import {
|
|
10010
|
-
import { basename as basename2, dirname, join as join2 } from "path";
|
|
10128
|
+
import { accessSync, constants, existsSync as existsSync4, renameSync, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
10129
|
+
import { basename as basename2, dirname, join as join3 } from "path";
|
|
10011
10130
|
import { promisify } from "util";
|
|
10012
10131
|
var execFileAsync = promisify(execFile);
|
|
10013
10132
|
function isMacOS() {
|
|
@@ -10045,7 +10164,7 @@ ${e.stdout ?? ""}`;
|
|
|
10045
10164
|
async function verifyBundleTrust(appPath, policy = {}) {
|
|
10046
10165
|
const identity = await readBundleIdentity(appPath);
|
|
10047
10166
|
const requireNotarized = policy.requireNotarized ?? true;
|
|
10048
|
-
if (!
|
|
10167
|
+
if (!existsSync4(appPath)) {
|
|
10049
10168
|
return { ok: false, identity, gatekeeperSource: null, reason: "unreadable", detail: `No such bundle: ${appPath}` };
|
|
10050
10169
|
}
|
|
10051
10170
|
try {
|
|
@@ -10104,17 +10223,19 @@ function findTopLevelApp(root) {
|
|
|
10104
10223
|
return parts[0] ?? null;
|
|
10105
10224
|
}
|
|
10106
10225
|
async function extractBundleFromDmg(dmgPath, stagingDir) {
|
|
10107
|
-
const staging = stagingDir ??
|
|
10108
|
-
const mountPoint =
|
|
10226
|
+
const staging = stagingDir ?? createTempDir("craft-update-");
|
|
10227
|
+
const mountPoint = createTempDir("craft-mount-");
|
|
10109
10228
|
let mounted = false;
|
|
10229
|
+
let staged = false;
|
|
10110
10230
|
try {
|
|
10111
10231
|
await execFileAsync("hdiutil", ["attach", dmgPath, "-nobrowse", "-readonly", "-mountpoint", mountPoint]);
|
|
10112
10232
|
mounted = true;
|
|
10113
10233
|
const source = findTopLevelApp(mountPoint);
|
|
10114
10234
|
if (!source)
|
|
10115
10235
|
throw new Error(`No .app found in disk image: ${dmgPath}`);
|
|
10116
|
-
const appPath =
|
|
10236
|
+
const appPath = join3(staging, basename2(source));
|
|
10117
10237
|
await dittoBundle(source, appPath);
|
|
10238
|
+
staged = true;
|
|
10118
10239
|
return { appPath, stagingDir: staging };
|
|
10119
10240
|
} finally {
|
|
10120
10241
|
if (mounted) {
|
|
@@ -10122,19 +10243,25 @@ async function extractBundleFromDmg(dmgPath, stagingDir) {
|
|
|
10122
10243
|
await execFileAsync("hdiutil", ["detach", mountPoint, "-force"]);
|
|
10123
10244
|
} catch {}
|
|
10124
10245
|
}
|
|
10125
|
-
|
|
10126
|
-
|
|
10127
|
-
|
|
10246
|
+
removeTempDir(mountPoint);
|
|
10247
|
+
if (!staged && !stagingDir)
|
|
10248
|
+
removeTempDir(staging);
|
|
10128
10249
|
}
|
|
10129
10250
|
}
|
|
10130
10251
|
async function extractBundleFromZip(zipPath, stagingDir) {
|
|
10131
|
-
const staging = stagingDir ??
|
|
10132
|
-
const unpacked =
|
|
10133
|
-
|
|
10134
|
-
|
|
10135
|
-
|
|
10136
|
-
|
|
10137
|
-
|
|
10252
|
+
const staging = stagingDir ?? createTempDir("craft-update-");
|
|
10253
|
+
const unpacked = join3(staging, "payload");
|
|
10254
|
+
try {
|
|
10255
|
+
await execFileAsync("ditto", ["-x", "-k", zipPath, unpacked]);
|
|
10256
|
+
const source = findTopLevelApp(unpacked);
|
|
10257
|
+
if (!source)
|
|
10258
|
+
throw new Error(`No .app found in archive: ${zipPath}`);
|
|
10259
|
+
return { appPath: source, stagingDir: staging };
|
|
10260
|
+
} catch (error) {
|
|
10261
|
+
if (!stagingDir)
|
|
10262
|
+
removeTempDir(staging);
|
|
10263
|
+
throw error;
|
|
10264
|
+
}
|
|
10138
10265
|
}
|
|
10139
10266
|
async function extractBundle(archivePath, stagingDir) {
|
|
10140
10267
|
if (archivePath.endsWith(".dmg"))
|
|
@@ -10144,18 +10271,18 @@ async function extractBundle(archivePath, stagingDir) {
|
|
|
10144
10271
|
throw new Error(`Cannot extract an app bundle from ${archivePath}`);
|
|
10145
10272
|
}
|
|
10146
10273
|
async function swapBundle(stagedPath, installedPath) {
|
|
10147
|
-
if (!
|
|
10274
|
+
if (!existsSync4(stagedPath))
|
|
10148
10275
|
throw new Error(`Staged bundle is missing: ${stagedPath}`);
|
|
10149
10276
|
const parent = dirname(installedPath);
|
|
10150
10277
|
const stamp = `${Date.now()}.${process.pid}`;
|
|
10151
|
-
const incoming =
|
|
10152
|
-
const retired =
|
|
10278
|
+
const incoming = join3(parent, `.${basename2(installedPath)}.${stamp}.incoming`);
|
|
10279
|
+
const retired = join3(parent, `.${basename2(installedPath)}.${stamp}.retired`);
|
|
10153
10280
|
try {
|
|
10154
10281
|
renameSync(stagedPath, incoming);
|
|
10155
10282
|
} catch {
|
|
10156
10283
|
await dittoBundle(stagedPath, incoming);
|
|
10157
10284
|
}
|
|
10158
|
-
const hadPrevious =
|
|
10285
|
+
const hadPrevious = existsSync4(installedPath);
|
|
10159
10286
|
try {
|
|
10160
10287
|
if (hadPrevious)
|
|
10161
10288
|
renameSync(installedPath, retired);
|
|
@@ -10171,13 +10298,13 @@ async function swapBundle(stagedPath, installedPath) {
|
|
|
10171
10298
|
}
|
|
10172
10299
|
} catch (error) {
|
|
10173
10300
|
try {
|
|
10174
|
-
|
|
10301
|
+
rmSync3(incoming, { recursive: true, force: true });
|
|
10175
10302
|
} catch {}
|
|
10176
10303
|
throw error;
|
|
10177
10304
|
}
|
|
10178
10305
|
if (hadPrevious) {
|
|
10179
10306
|
try {
|
|
10180
|
-
|
|
10307
|
+
rmSync3(retired, { recursive: true, force: true });
|
|
10181
10308
|
return { previousPath: null };
|
|
10182
10309
|
} catch {
|
|
10183
10310
|
return { previousPath: retired };
|
|
@@ -10189,8 +10316,8 @@ function canReplaceBundle(installedPath) {
|
|
|
10189
10316
|
try {
|
|
10190
10317
|
const parent = dirname(installedPath);
|
|
10191
10318
|
accessSync(parent, constants.W_OK);
|
|
10192
|
-
if (
|
|
10193
|
-
|
|
10319
|
+
if (existsSync4(installedPath))
|
|
10320
|
+
statSync2(installedPath);
|
|
10194
10321
|
return true;
|
|
10195
10322
|
} catch {
|
|
10196
10323
|
return false;
|
|
@@ -10229,7 +10356,7 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10229
10356
|
downloadDir() {
|
|
10230
10357
|
if (this.config.downloadDir)
|
|
10231
10358
|
return this.config.downloadDir;
|
|
10232
|
-
return
|
|
10359
|
+
return join4(tmpdir2(), "craft-updates", basename3(this.config.appPath) || "app");
|
|
10233
10360
|
}
|
|
10234
10361
|
getLastError() {
|
|
10235
10362
|
return this.lastError;
|
|
@@ -10330,7 +10457,7 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10330
10457
|
const downloadDir = this.downloadDir();
|
|
10331
10458
|
mkdirSync2(downloadDir, { recursive: true });
|
|
10332
10459
|
const fileName = basename3(url);
|
|
10333
|
-
this.downloadPath =
|
|
10460
|
+
this.downloadPath = join4(downloadDir, fileName);
|
|
10334
10461
|
try {
|
|
10335
10462
|
const response = await fetch(url);
|
|
10336
10463
|
if (!response.ok) {
|
|
@@ -10393,11 +10520,11 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10393
10520
|
throw new Error("Download verification failed: hash mismatch");
|
|
10394
10521
|
}
|
|
10395
10522
|
if (deltaUpdate) {
|
|
10396
|
-
if (!
|
|
10523
|
+
if (!statSync3(this.config.appPath).isFile()) {
|
|
10397
10524
|
throw new Error("Delta updates require appPath to point to the installed bundle file");
|
|
10398
10525
|
}
|
|
10399
10526
|
const patchPath = this.downloadPath;
|
|
10400
|
-
const reconstructedPath =
|
|
10527
|
+
const reconstructedPath = join4(downloadDir, `reconstructed-${basename3(platformUpdate.url)}`);
|
|
10401
10528
|
await DeltaGenerator.apply(this.config.appPath, patchPath, reconstructedPath);
|
|
10402
10529
|
const reconstructedHash = await this.computeFileHash(reconstructedPath);
|
|
10403
10530
|
if (reconstructedHash !== platformUpdate.sha256) {
|
|
@@ -10435,7 +10562,7 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10435
10562
|
}
|
|
10436
10563
|
}
|
|
10437
10564
|
async installUpdate(restartAfter = true) {
|
|
10438
|
-
if (!this.downloadPath || !
|
|
10565
|
+
if (!this.downloadPath || !existsSync5(this.downloadPath)) {
|
|
10439
10566
|
throw new Error("No update downloaded");
|
|
10440
10567
|
}
|
|
10441
10568
|
if (this.updateInfo) {
|
|
@@ -10479,7 +10606,7 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10479
10606
|
await this.installLinuxUpdate();
|
|
10480
10607
|
break;
|
|
10481
10608
|
}
|
|
10482
|
-
if (this.downloadPath &&
|
|
10609
|
+
if (this.downloadPath && existsSync5(this.downloadPath)) {
|
|
10483
10610
|
unlinkSync(this.downloadPath);
|
|
10484
10611
|
}
|
|
10485
10612
|
try {
|
|
@@ -10519,9 +10646,7 @@ class AutoUpdater extends EventEmitter3 {
|
|
|
10519
10646
|
leftoverPath: previousPath
|
|
10520
10647
|
});
|
|
10521
10648
|
} finally {
|
|
10522
|
-
|
|
10523
|
-
rmSync3(staged.stagingDir, { recursive: true, force: true });
|
|
10524
|
-
} catch {}
|
|
10649
|
+
removeTempDir(staged.stagingDir);
|
|
10525
10650
|
}
|
|
10526
10651
|
}
|
|
10527
10652
|
async assertBundleTrusted(bundlePath) {
|
|
@@ -10682,7 +10807,7 @@ class DeltaGenerator {
|
|
|
10682
10807
|
static async generate(oldPath, newPath, outputPath) {
|
|
10683
10808
|
try {
|
|
10684
10809
|
execFileSync2("bsdiff", [oldPath, newPath, outputPath]);
|
|
10685
|
-
const stats =
|
|
10810
|
+
const stats = statSync3(outputPath);
|
|
10686
10811
|
const hash = await DeltaGenerator.computeHash(outputPath);
|
|
10687
10812
|
return {
|
|
10688
10813
|
size: stats.size,
|
|
@@ -10690,7 +10815,7 @@ class DeltaGenerator {
|
|
|
10690
10815
|
};
|
|
10691
10816
|
} catch {
|
|
10692
10817
|
execFileSync2("xdelta3", ["-e", "-s", oldPath, newPath, outputPath]);
|
|
10693
|
-
const stats =
|
|
10818
|
+
const stats = statSync3(outputPath);
|
|
10694
10819
|
const hash = await DeltaGenerator.computeHash(outputPath);
|
|
10695
10820
|
return {
|
|
10696
10821
|
size: stats.size,
|
|
@@ -10804,7 +10929,7 @@ ${update.releaseNotes}`);
|
|
|
10804
10929
|
releaseDate: new Date().toISOString(),
|
|
10805
10930
|
platforms: {}
|
|
10806
10931
|
};
|
|
10807
|
-
|
|
10932
|
+
writeFileSync3(outputPath, JSON.stringify(manifest, null, 2));
|
|
10808
10933
|
console.log(`Manifest generated: ${outputPath}`);
|
|
10809
10934
|
console.log("Edit the file to add platform-specific update URLs");
|
|
10810
10935
|
break;
|
|
@@ -10892,6 +11017,7 @@ function detectDevMode() {
|
|
|
10892
11017
|
class CraftApp {
|
|
10893
11018
|
process;
|
|
10894
11019
|
config;
|
|
11020
|
+
sidebarConfigDir;
|
|
10895
11021
|
constructor(config = {}) {
|
|
10896
11022
|
if (config.window?.width !== undefined && (config.window.width < 100 || config.window.width > 1e4)) {
|
|
10897
11023
|
throw new Error(`Invalid window width: ${config.window.width}. Must be between 100 and 10000 pixels.`);
|
|
@@ -10928,8 +11054,15 @@ class CraftApp {
|
|
|
10928
11054
|
throw new Error(`No content to display. Provide either html or url:
|
|
10929
11055
|
` + " show(html, options) or loadURL(url, options)");
|
|
10930
11056
|
}
|
|
11057
|
+
this.removeSidebarConfig();
|
|
10931
11058
|
const args = this.buildArgs();
|
|
10932
|
-
|
|
11059
|
+
let craftPath;
|
|
11060
|
+
try {
|
|
11061
|
+
craftPath = await this.findCraftBinary();
|
|
11062
|
+
} catch (error) {
|
|
11063
|
+
this.removeSidebarConfig();
|
|
11064
|
+
throw error;
|
|
11065
|
+
}
|
|
10933
11066
|
probeBinaryVersion(craftPath);
|
|
10934
11067
|
const quiet = this.config.quiet === true;
|
|
10935
11068
|
this.process = spawn4(craftPath, args, {
|
|
@@ -10942,6 +11075,7 @@ class CraftApp {
|
|
|
10942
11075
|
});
|
|
10943
11076
|
return new Promise((resolve, reject) => {
|
|
10944
11077
|
this.process?.on("error", (error) => {
|
|
11078
|
+
this.removeSidebarConfig();
|
|
10945
11079
|
if (error.code === "ENOENT") {
|
|
10946
11080
|
reject(new Error(craftBinaryNotFoundMessage(craftPath)));
|
|
10947
11081
|
return;
|
|
@@ -10959,6 +11093,7 @@ class CraftApp {
|
|
|
10959
11093
|
` + " https://github.com/home-lang/craft/issues"));
|
|
10960
11094
|
});
|
|
10961
11095
|
this.process?.on("close", (code) => {
|
|
11096
|
+
this.removeSidebarConfig();
|
|
10962
11097
|
if (code === 0 || code === null) {
|
|
10963
11098
|
resolve();
|
|
10964
11099
|
} else {
|
|
@@ -10976,6 +11111,12 @@ class CraftApp {
|
|
|
10976
11111
|
this.process.kill();
|
|
10977
11112
|
}
|
|
10978
11113
|
}
|
|
11114
|
+
removeSidebarConfig() {
|
|
11115
|
+
if (!this.sidebarConfigDir)
|
|
11116
|
+
return;
|
|
11117
|
+
removeTempDir(this.sidebarConfigDir);
|
|
11118
|
+
this.sidebarConfigDir = undefined;
|
|
11119
|
+
}
|
|
10979
11120
|
buildArgs() {
|
|
10980
11121
|
const args = [];
|
|
10981
11122
|
const { window: window3, html, url, appName } = this.config;
|
|
@@ -11074,9 +11215,10 @@ class CraftApp {
|
|
|
11074
11215
|
if (safeForArgv) {
|
|
11075
11216
|
args.push("--sidebar-config", json);
|
|
11076
11217
|
} else {
|
|
11077
|
-
const dir =
|
|
11078
|
-
|
|
11079
|
-
|
|
11218
|
+
const dir = createTempDir("craft-sidebar-");
|
|
11219
|
+
this.sidebarConfigDir = dir;
|
|
11220
|
+
const path = join5(dir, "sidebar-config.json");
|
|
11221
|
+
writeFileSync4(path, json, "utf-8");
|
|
11080
11222
|
args.push("--sidebar-config-file", path);
|
|
11081
11223
|
}
|
|
11082
11224
|
}
|