craft-native 0.0.186 → 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 CHANGED
@@ -17,6 +17,119 @@ var __export = (target, all) => {
17
17
  var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
18
18
  var __require = import.meta.require;
19
19
 
20
+ // src/temp-dir.ts
21
+ import { existsSync as existsSync3, mkdtempSync, readdirSync, rmSync, statSync, writeFileSync as writeFileSync2 } from "fs";
22
+ import { constants as osConstants, tmpdir } from "os";
23
+ import { join } from "path";
24
+ function removeQuietly(dir) {
25
+ try {
26
+ rmSync(dir, { recursive: true, force: true });
27
+ } catch {}
28
+ }
29
+ function removeAllTempDirs() {
30
+ for (const dir of live)
31
+ removeQuietly(dir);
32
+ live.clear();
33
+ unhook();
34
+ }
35
+ function onExit() {
36
+ for (const dir of live)
37
+ removeQuietly(dir);
38
+ live.clear();
39
+ }
40
+ function onSignal(signal) {
41
+ removeAllTempDirs();
42
+ if (process.listenerCount(signal) === 0)
43
+ process.exit(128 + (osConstants.signals[signal] ?? 1));
44
+ }
45
+ function hook() {
46
+ if (hooked)
47
+ return;
48
+ hooked = true;
49
+ process.on("exit", onExit);
50
+ for (const [signal, handler] of signalHandlers) {
51
+ try {
52
+ process.on(signal, handler);
53
+ } catch {}
54
+ }
55
+ }
56
+ function unhook() {
57
+ if (!hooked)
58
+ return;
59
+ hooked = false;
60
+ process.off("exit", onExit);
61
+ for (const [signal, handler] of signalHandlers)
62
+ process.off(signal, handler);
63
+ }
64
+ function pidIsAlive(pid) {
65
+ try {
66
+ process.kill(pid, 0);
67
+ return true;
68
+ } catch (error) {
69
+ return error.code === "EPERM";
70
+ }
71
+ }
72
+ function sweepOrphanedTempDirs(options = {}) {
73
+ const root = options.root ?? tmpdir();
74
+ const isAlive = options.isAlive ?? pidIsAlive;
75
+ const minAge = options.minAgeMs ?? SWEEP_MIN_AGE_MS;
76
+ const now = options.now ?? Date.now();
77
+ const removed = [];
78
+ let names;
79
+ try {
80
+ names = readdirSync(root);
81
+ } catch {
82
+ return removed;
83
+ }
84
+ for (const name of names) {
85
+ const match = OWNED_NAME.exec(name);
86
+ if (!match)
87
+ continue;
88
+ const pid = Number(match[1]);
89
+ if (pid === process.pid || isAlive(pid))
90
+ continue;
91
+ const path2 = join(root, name);
92
+ try {
93
+ if (now - statSync(path2).mtimeMs < minAge)
94
+ continue;
95
+ if (existsSync3(join(path2, KEEP_MARKER)))
96
+ continue;
97
+ } catch {
98
+ continue;
99
+ }
100
+ removeQuietly(path2);
101
+ removed.push(path2);
102
+ }
103
+ return removed;
104
+ }
105
+ function tempDirPrefix(label) {
106
+ const bare = label.replace(/^craft-/, "").replace(/-+$/, "");
107
+ return bare ? `craft-${bare}-p${process.pid}-` : `craft-p${process.pid}-`;
108
+ }
109
+ function createTempDir(label, root = tmpdir()) {
110
+ if (!swept) {
111
+ swept = true;
112
+ sweepOrphanedTempDirs({ root });
113
+ }
114
+ hook();
115
+ const dir = mkdtempSync(join(root, tempDirPrefix(label)));
116
+ live.add(dir);
117
+ return dir;
118
+ }
119
+ function removeTempDir(dir) {
120
+ removeQuietly(dir);
121
+ live.delete(dir);
122
+ if (live.size === 0)
123
+ unhook();
124
+ }
125
+ var OWNED_NAME, KEEP_MARKER = ".craft-keep", SWEEP_MIN_AGE_MS = 60000, SIGNALS, live, hooked = false, swept = false, signalHandlers;
126
+ var init_temp_dir = __esm(() => {
127
+ OWNED_NAME = /^craft-(?:.+-)?p(\d+)-[A-Za-z0-9]{6}$/;
128
+ SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
129
+ live = new Set;
130
+ signalHandlers = new Map(SIGNALS.map((signal) => [signal, () => onSignal(signal)]));
131
+ });
132
+
20
133
  // src/package.ts
21
134
  var exports_package = {};
22
135
  __export(exports_package, {
@@ -48,17 +161,16 @@ import {
48
161
  chmodSync,
49
162
  copyFileSync,
50
163
  cpSync,
51
- existsSync as existsSync3,
164
+ existsSync as existsSync4,
52
165
  lstatSync,
53
166
  mkdirSync,
54
- mkdtempSync,
55
167
  readFileSync as readFileSync2,
56
- readdirSync,
57
- rmSync,
58
- writeFileSync as writeFileSync2
168
+ readdirSync as readdirSync2,
169
+ rmSync as rmSync2,
170
+ writeFileSync as writeFileSync3
59
171
  } from "fs";
60
- import { homedir, tmpdir } from "os";
61
- import { basename, join } from "path";
172
+ import { homedir } from "os";
173
+ import { basename, join as join2 } from "path";
62
174
  import { deflateRawSync } from "zlib";
63
175
  function crc32(data) {
64
176
  let c = 4294967295;
@@ -132,12 +244,12 @@ function formatPackagingCommandError(tool, code, stdout3, stderr) {
132
244
  }
133
245
  async function packageApp(config) {
134
246
  const results = [];
135
- if (!config.binaryPath || !existsSync3(config.binaryPath)) {
247
+ if (!config.binaryPath || !existsSync4(config.binaryPath)) {
136
248
  throw new Error(`Binary not found: ${config.binaryPath}`);
137
249
  }
138
250
  const platforms = config.platforms || [detectPlatform()];
139
- const outDir = config.outDir || join(process.cwd(), "dist");
140
- if (!existsSync3(outDir)) {
251
+ const outDir = config.outDir || join2(process.cwd(), "dist");
252
+ if (!existsSync4(outDir)) {
141
253
  mkdirSync(outDir, { recursive: true });
142
254
  }
143
255
  for (const platform of platforms) {
@@ -160,7 +272,7 @@ async function packageMacOS(config, outDir) {
160
272
  const { name, version: version2, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
161
273
  const opts = config.macos || {};
162
274
  const hardenedRuntime = !opts.appStore;
163
- const appBundlePath = join(outDir, `${name}.app`);
275
+ const appBundlePath = join2(outDir, `${name}.app`);
164
276
  const appBundle = createMacOSAppBundle({
165
277
  name,
166
278
  version: version2,
@@ -207,7 +319,7 @@ async function packageMacOS(config, outDir) {
207
319
  }
208
320
  results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
209
321
  if (opts.dmg !== false) {
210
- const outputPath = join(outDir, `${name}-${version2}.dmg`);
322
+ const outputPath = join2(outDir, `${name}-${version2}.dmg`);
211
323
  const dmgResult = await createDMG({ appBundlePath, outputPath, volumeName: name });
212
324
  results.push({
213
325
  success: dmgResult.success,
@@ -220,7 +332,7 @@ async function packageMacOS(config, outDir) {
220
332
  results.push(...await notarizeIfRequested(opts, outputPath, "dmg"));
221
333
  }
222
334
  if (opts.pkg || opts.appStore) {
223
- const outputPath = join(outDir, `${name}-${version2}.pkg`);
335
+ const outputPath = join2(outDir, `${name}-${version2}.pkg`);
224
336
  const pkgResult = await createPKG({
225
337
  appBundlePath,
226
338
  outputPath,
@@ -278,7 +390,7 @@ async function packageWindows(config, outDir) {
278
390
  name,
279
391
  version: version2,
280
392
  binaryPath: config.binaryPath,
281
- outputPath: join(outDir, `${name}-${version2}.msi`),
393
+ outputPath: join2(outDir, `${name}-${version2}.msi`),
282
394
  manufacturer: config.author || "Unknown",
283
395
  architecture: opts.architecture || windowsArchitecture(process.arch),
284
396
  additionalFiles: opts.additionalFiles,
@@ -302,7 +414,7 @@ async function packageWindows(config, outDir) {
302
414
  manufacturer: config.author || "Unknown",
303
415
  binaryPath: config.binaryPath,
304
416
  additionalFiles: opts.additionalFiles,
305
- outputPath: join(outDir, `${name}-${version2}-windows.zip`)
417
+ outputPath: join2(outDir, `${name}-${version2}-windows.zip`)
306
418
  });
307
419
  results.push({
308
420
  success: zipResult.success,
@@ -323,7 +435,7 @@ async function packageLinux(config, outDir) {
323
435
  name,
324
436
  version: version2,
325
437
  binaryPath: config.binaryPath,
326
- outputPath: join(outDir, `${name}_${version2}_amd64.deb`),
438
+ outputPath: join2(outDir, `${name}_${version2}_amd64.deb`),
327
439
  description: config.description || "",
328
440
  maintainer: config.author || "Unknown",
329
441
  dependencies: opts.debDependencies || [...DEFAULT_DEB_DEPENDENCIES],
@@ -343,7 +455,7 @@ async function packageLinux(config, outDir) {
343
455
  name,
344
456
  version: version2,
345
457
  binaryPath: config.binaryPath,
346
- outputPath: join(outDir, `${name}-${version2}-1.x86_64.rpm`),
458
+ outputPath: join2(outDir, `${name}-${version2}-1.x86_64.rpm`),
347
459
  description: config.description || "",
348
460
  requires: opts.rpmDependencies || ["gtk3", "webkit2gtk3"]
349
461
  });
@@ -360,7 +472,7 @@ async function packageLinux(config, outDir) {
360
472
  name,
361
473
  version: version2,
362
474
  binaryPath: config.binaryPath,
363
- outputPath: join(outDir, `${name}-${version2}-x86_64.AppImage`),
475
+ outputPath: join2(outDir, `${name}-${version2}-x86_64.AppImage`),
364
476
  iconPath: config.iconPath
365
477
  });
366
478
  results.push({
@@ -504,32 +616,32 @@ function notarytoolArguments(opts) {
504
616
  function createMacOSAppBundle(opts) {
505
617
  try {
506
618
  const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
507
- const contents = join(outputPath, "Contents");
508
- const macOS = join(contents, "MacOS");
619
+ const contents = join2(outputPath, "Contents");
620
+ const macOS = join2(contents, "MacOS");
509
621
  mkdirSync(macOS, { recursive: true });
510
- mkdirSync(join(contents, "Resources"), { recursive: true });
511
- copyFileSync(binaryPath, join(macOS, name));
512
- chmodSync(join(macOS, name), 493);
622
+ mkdirSync(join2(contents, "Resources"), { recursive: true });
623
+ copyFileSync(binaryPath, join2(macOS, name));
624
+ chmodSync(join2(macOS, name), 493);
513
625
  for (const executable of additionalExecutables || []) {
514
- if (!existsSync3(executable))
626
+ if (!existsSync4(executable))
515
627
  return { success: false, error: `Additional executable not found: ${executable}` };
516
- const destination = join(macOS, basename(executable));
628
+ const destination = join2(macOS, basename(executable));
517
629
  copyFileSync(executable, destination);
518
630
  chmodSync(destination, 493);
519
631
  }
520
632
  let iconName;
521
633
  if (iconPath) {
522
- if (!existsSync3(iconPath))
634
+ if (!existsSync4(iconPath))
523
635
  return { success: false, error: `Icon not found: ${iconPath}` };
524
636
  iconName = basename(iconPath).replace(/\.icns$/i, "");
525
- copyFileSync(iconPath, join(contents, "Resources", `${iconName}.icns`));
637
+ copyFileSync(iconPath, join2(contents, "Resources", `${iconName}.icns`));
526
638
  }
527
639
  if (provisioningProfile) {
528
- if (!existsSync3(provisioningProfile))
640
+ if (!existsSync4(provisioningProfile))
529
641
  return { success: false, error: `Provisioning profile not found: ${provisioningProfile}` };
530
- copyFileSync(provisioningProfile, join(contents, "embedded.provisionprofile"));
642
+ copyFileSync(provisioningProfile, join2(contents, "embedded.provisionprofile"));
531
643
  }
532
- writeFileSync2(join(contents, "Info.plist"), macOSInfoPlist({ ...opts, iconName }));
644
+ writeFileSync3(join2(contents, "Info.plist"), macOSInfoPlist({ ...opts, iconName }));
533
645
  return { success: true };
534
646
  } catch (error) {
535
647
  return { success: false, error: error.message };
@@ -539,7 +651,7 @@ function pathContentBytes(path2) {
539
651
  const stat = lstatSync(path2);
540
652
  if (!stat.isDirectory())
541
653
  return stat.size;
542
- return readdirSync(path2).reduce((total, entry) => total + pathContentBytes(join(path2, entry)), 0);
654
+ return readdirSync2(path2).reduce((total, entry) => total + pathContentBytes(join2(path2, entry)), 0);
543
655
  }
544
656
  function dmgCapacityMegabytes(contentBytes) {
545
657
  if (!Number.isSafeInteger(contentBytes) || contentBytes < 0)
@@ -600,7 +712,7 @@ async function createDMG(opts) {
600
712
  if (!shouldRetryHdiutil(result.error, attempt))
601
713
  return { success: false, error: failures.join(`
602
714
  `) };
603
- rmSync(opts.outputPath, { force: true });
715
+ rmSync2(opts.outputPath, { force: true });
604
716
  await new Promise((resolve) => setTimeout(resolve, attempt * 2000));
605
717
  }
606
718
  return { success: false, error: failures.join(`
@@ -658,16 +770,16 @@ async function createPKG(opts) {
658
770
  }));
659
771
  return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
660
772
  }
661
- const tempDir = mkdtempSync(join(tmpdir(), "craft-pkg-"));
773
+ const tempDir = createTempDir("craft-pkg-");
662
774
  try {
663
- const root = join(tempDir, "root");
664
- const appsDir = join(root, "Applications");
775
+ const root = join2(tempDir, "root");
776
+ const appsDir = join2(root, "Applications");
665
777
  mkdirSync(appsDir, { recursive: true, mode: 493 });
666
778
  chmodSync(root, 493);
667
779
  const bundleName = basename(opts.appBundlePath);
668
- cpSync(opts.appBundlePath, join(appsDir, bundleName), { recursive: true });
669
- const componentPlistPath = join(tempDir, "component.plist");
670
- writeFileSync2(componentPlistPath, pkgbuildComponentPlist(`Applications/${bundleName}`));
780
+ cpSync(opts.appBundlePath, join2(appsDir, bundleName), { recursive: true });
781
+ const componentPlistPath = join2(tempDir, "component.plist");
782
+ writeFileSync3(componentPlistPath, pkgbuildComponentPlist(`Applications/${bundleName}`));
671
783
  const built = await runTool("pkgbuild", pkgbuildArguments({
672
784
  root,
673
785
  componentPlistPath,
@@ -678,7 +790,7 @@ async function createPKG(opts) {
678
790
  }));
679
791
  return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
680
792
  } finally {
681
- rmSync(tempDir, { recursive: true, force: true });
793
+ removeTempDir(tempDir);
682
794
  }
683
795
  }
684
796
  function xml(value) {
@@ -774,7 +886,7 @@ function windowsCompanionFiles(paths, executableName) {
774
886
  if (seen.has(name.toLowerCase()))
775
887
  throw new Error(`Duplicate Windows package file: ${name}`);
776
888
  seen.add(name.toLowerCase());
777
- if (!existsSync3(path2) || lstatSync(path2).isDirectory())
889
+ if (!existsSync4(path2) || lstatSync(path2).isDirectory())
778
890
  throw new Error(`Windows companion file not found: ${path2}`);
779
891
  return { path: path2, name };
780
892
  });
@@ -797,18 +909,18 @@ function runCommand(command, args, cwd) {
797
909
  });
798
910
  }
799
911
  async function createMSI(opts) {
800
- const tempDir = mkdtempSync(join(tmpdir(), "craft-msi-"));
912
+ const tempDir = createTempDir("craft-msi-");
801
913
  try {
802
914
  const binaryName = windowsExecutableName(opts.name);
803
915
  const additionalFiles = windowsCompanionFiles(opts.additionalFiles, binaryName);
804
- const sourcePath = join(tempDir, binaryName);
805
- const wxsPath = join(tempDir, "installer.wxs");
806
- const wixobjPath = join(tempDir, "installer.wixobj");
916
+ const sourcePath = join2(tempDir, binaryName);
917
+ const wxsPath = join2(tempDir, "installer.wxs");
918
+ const wixobjPath = join2(tempDir, "installer.wixobj");
807
919
  copyFileSync(opts.binaryPath, sourcePath);
808
- writeFileSync2(join(tempDir, WINDOWS_NOTIFICATION_ID_FILE), windowsNotificationAppId(opts.name, opts.manufacturer));
920
+ writeFileSync3(join2(tempDir, WINDOWS_NOTIFICATION_ID_FILE), windowsNotificationAppId(opts.name, opts.manufacturer));
809
921
  for (const file of additionalFiles)
810
- copyFileSync(file.path, join(tempDir, file.name));
811
- writeFileSync2(wxsPath, renderWixSource(opts, binaryName, additionalFiles.map((file) => file.name)));
922
+ copyFileSync(file.path, join2(tempDir, file.name));
923
+ writeFileSync3(wxsPath, renderWixSource(opts, binaryName, additionalFiles.map((file) => file.name)));
812
924
  await runCommand("candle.exe", candleArguments(opts.architecture, wixobjPath, wxsPath), tempDir);
813
925
  await runCommand("light.exe", ["-nologo", "-sval", "-out", opts.outputPath, wixobjPath], tempDir);
814
926
  if (opts.certificatePath) {
@@ -825,7 +937,7 @@ async function createMSI(opts) {
825
937
  const missingTool = /ENOENT|not found/i.test(message);
826
938
  return { success: false, error: missingTool ? `WiX Toolset not found: ${message}` : message };
827
939
  } finally {
828
- rmSync(tempDir, { recursive: true, force: true });
940
+ removeTempDir(tempDir);
829
941
  }
830
942
  }
831
943
  async function createZIP(opts) {
@@ -837,7 +949,7 @@ async function createZIP(opts) {
837
949
  for (const file of additionalFiles)
838
950
  entries.push({ name: file.name, data: new Uint8Array(readFileSync2(file.path)) });
839
951
  const zip = buildZip(entries);
840
- writeFileSync2(opts.outputPath, zip);
952
+ writeFileSync3(opts.outputPath, zip);
841
953
  return { success: true, outputPath: opts.outputPath };
842
954
  } catch (err) {
843
955
  return { success: false, error: `Failed to write ZIP: ${err.message}` };
@@ -845,6 +957,7 @@ async function createZIP(opts) {
845
957
  }
846
958
  async function createDEB(opts) {
847
959
  return new Promise((resolve) => {
960
+ let staging;
848
961
  try {
849
962
  const sanitizedName = opts.name.toLowerCase();
850
963
  const safeDebName = /^[a-z0-9._+-]+$/;
@@ -867,16 +980,17 @@ async function createDEB(opts) {
867
980
  }
868
981
  }
869
982
  const desktopContent = linuxDesktopEntry(opts.name, sanitizedName, opts.urlSchemes, opts.launchUrl);
870
- const tempDir = mkdtempSync(join(tmpdir(), "craft-deb-"));
871
- const debianDir = join(tempDir, "DEBIAN");
872
- const binDir = join(tempDir, "usr", "bin");
873
- const applicationsDir = join(tempDir, "usr", "share", "applications");
983
+ const tempDir = createTempDir("craft-deb-");
984
+ staging = tempDir;
985
+ const debianDir = join2(tempDir, "DEBIAN");
986
+ const binDir = join2(tempDir, "usr", "bin");
987
+ const applicationsDir = join2(tempDir, "usr", "share", "applications");
874
988
  mkdirSync(debianDir, { recursive: true });
875
989
  mkdirSync(binDir, { recursive: true });
876
990
  mkdirSync(applicationsDir, { recursive: true });
877
991
  const binaryName = sanitizedName;
878
- copyFileSync(opts.binaryPath, join(binDir, binaryName));
879
- chmodSync(join(binDir, binaryName), 493);
992
+ copyFileSync(opts.binaryPath, join2(binDir, binaryName));
993
+ chmodSync(join2(binDir, binaryName), 493);
880
994
  const controlContent = `Package: ${sanitizedName}
881
995
  Version: ${opts.version}
882
996
  Section: utils
@@ -886,11 +1000,11 @@ Depends: ${opts.dependencies.join(", ")}
886
1000
  Maintainer: ${maintainer}
887
1001
  Description: ${description || opts.name}
888
1002
  `;
889
- writeFileSync2(join(debianDir, "control"), controlContent);
890
- writeFileSync2(join(applicationsDir, `${binaryName}.desktop`), desktopContent);
1003
+ writeFileSync3(join2(debianDir, "control"), controlContent);
1004
+ writeFileSync3(join2(applicationsDir, `${binaryName}.desktop`), desktopContent);
891
1005
  const proc = spawn("dpkg-deb", ["--build", tempDir, opts.outputPath]);
892
1006
  proc.on("close", (code) => {
893
- rmSync(tempDir, { recursive: true, force: true });
1007
+ removeTempDir(tempDir);
894
1008
  if (code === 0) {
895
1009
  resolve({ success: true, outputPath: opts.outputPath });
896
1010
  } else {
@@ -898,10 +1012,12 @@ Description: ${description || opts.name}
898
1012
  }
899
1013
  });
900
1014
  proc.on("error", (err) => {
901
- rmSync(tempDir, { recursive: true, force: true });
1015
+ removeTempDir(tempDir);
902
1016
  resolve({ success: false, error: err.message });
903
1017
  });
904
1018
  } catch (error) {
1019
+ if (staging)
1020
+ removeTempDir(staging);
905
1021
  resolve({ success: false, error: error.message });
906
1022
  }
907
1023
  });
@@ -909,11 +1025,11 @@ Description: ${description || opts.name}
909
1025
  async function createRPM(opts) {
910
1026
  return new Promise((resolve) => {
911
1027
  try {
912
- const buildRoot = join(homedir(), "rpmbuild");
913
- const specDir = join(buildRoot, "SPECS");
914
- const sourcesDir = join(buildRoot, "SOURCES");
915
- const buildDir = join(buildRoot, "BUILD");
916
- const rpmsDir = join(buildRoot, "RPMS");
1028
+ const buildRoot = join2(homedir(), "rpmbuild");
1029
+ const specDir = join2(buildRoot, "SPECS");
1030
+ const sourcesDir = join2(buildRoot, "SOURCES");
1031
+ const buildDir = join2(buildRoot, "BUILD");
1032
+ const rpmsDir = join2(buildRoot, "RPMS");
917
1033
  mkdirSync(specDir, { recursive: true });
918
1034
  mkdirSync(sourcesDir, { recursive: true });
919
1035
  mkdirSync(buildDir, { recursive: true });
@@ -937,7 +1053,7 @@ async function createRPM(opts) {
937
1053
  }
938
1054
  return r;
939
1055
  }).join(", ");
940
- copyFileSync(opts.binaryPath, join(sourcesDir, sanitizedName));
1056
+ copyFileSync(opts.binaryPath, join2(sourcesDir, sanitizedName));
941
1057
  const specContent = `Name: ${sanitizedName}
942
1058
  Version: ${opts.version}
943
1059
  Release: 1%{?dist}
@@ -955,13 +1071,13 @@ install -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}
955
1071
  %files
956
1072
  /usr/bin/${sanitizedName}
957
1073
  `;
958
- const specPath = join(specDir, `${opts.name.toLowerCase()}.spec`);
959
- writeFileSync2(specPath, specContent);
1074
+ const specPath = join2(specDir, `${opts.name.toLowerCase()}.spec`);
1075
+ writeFileSync3(specPath, specContent);
960
1076
  const proc = spawn("rpmbuild", ["-bb", specPath]);
961
1077
  proc.on("close", (code) => {
962
1078
  if (code === 0) {
963
1079
  const rpmName = `${opts.name.toLowerCase()}-${opts.version}-1.x86_64.rpm`;
964
- const builtRpmPath = join(rpmsDir, "x86_64", rpmName);
1080
+ const builtRpmPath = join2(rpmsDir, "x86_64", rpmName);
965
1081
  try {
966
1082
  copyFileSync(builtRpmPath, opts.outputPath);
967
1083
  resolve({ success: true, outputPath: opts.outputPath });
@@ -982,24 +1098,26 @@ install -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}
982
1098
  }
983
1099
  async function createAppImage(opts) {
984
1100
  return new Promise((resolve) => {
1101
+ let staging;
985
1102
  try {
986
- const appDir = mkdtempSync(join(tmpdir(), "craft-appimage-"));
987
- const appDirPath = join(appDir, `${opts.name}.AppDir`);
988
- const binDir = join(appDirPath, "usr", "bin");
989
- const shareDir = join(appDirPath, "usr", "share");
1103
+ const appDir = createTempDir("craft-appimage-");
1104
+ staging = appDir;
1105
+ const appDirPath = join2(appDir, `${opts.name}.AppDir`);
1106
+ const binDir = join2(appDirPath, "usr", "bin");
1107
+ const shareDir = join2(appDirPath, "usr", "share");
990
1108
  mkdirSync(binDir, { recursive: true });
991
1109
  mkdirSync(shareDir, { recursive: true });
992
1110
  const binaryName = opts.name.toLowerCase();
993
- copyFileSync(opts.binaryPath, join(binDir, binaryName));
994
- chmodSync(join(binDir, binaryName), 493);
1111
+ copyFileSync(opts.binaryPath, join2(binDir, binaryName));
1112
+ chmodSync(join2(binDir, binaryName), 493);
995
1113
  const appRunContent = `#!/bin/bash
996
1114
  SELF=$(readlink -f "$0")
997
1115
  HERE=\${SELF%/*}
998
1116
  export PATH="\${HERE}/usr/bin/:\${PATH}"
999
1117
  exec "\${HERE}/usr/bin/${binaryName}" "$@"
1000
1118
  `;
1001
- writeFileSync2(join(appDirPath, "AppRun"), appRunContent);
1002
- chmodSync(join(appDirPath, "AppRun"), 493);
1119
+ writeFileSync3(join2(appDirPath, "AppRun"), appRunContent);
1120
+ chmodSync(join2(appDirPath, "AppRun"), 493);
1003
1121
  const desktopContent = `[Desktop Entry]
1004
1122
  Type=Application
1005
1123
  Name=${opts.name}
@@ -1008,9 +1126,9 @@ Terminal=false
1008
1126
  Categories=Utility;
1009
1127
  Icon=${binaryName}
1010
1128
  `;
1011
- writeFileSync2(join(appDirPath, `${binaryName}.desktop`), desktopContent);
1012
- if (opts.iconPath && existsSync3(opts.iconPath)) {
1013
- copyFileSync(opts.iconPath, join(appDirPath, `${binaryName}.png`));
1129
+ writeFileSync3(join2(appDirPath, `${binaryName}.desktop`), desktopContent);
1130
+ if (opts.iconPath && existsSync4(opts.iconPath)) {
1131
+ copyFileSync(opts.iconPath, join2(appDirPath, `${binaryName}.png`));
1014
1132
  } else {
1015
1133
  const placeholderPng = Buffer.from([
1016
1134
  137,
@@ -1083,13 +1201,13 @@ Icon=${binaryName}
1083
1201
  96,
1084
1202
  130
1085
1203
  ]);
1086
- writeFileSync2(join(appDirPath, `${binaryName}.png`), placeholderPng);
1204
+ writeFileSync3(join2(appDirPath, `${binaryName}.png`), placeholderPng);
1087
1205
  }
1088
1206
  const proc = spawn("appimagetool", [appDirPath, opts.outputPath], {
1089
1207
  env: { ...process.env, ARCH: "x86_64" }
1090
1208
  });
1091
1209
  proc.on("close", (code) => {
1092
- rmSync(appDir, { recursive: true, force: true });
1210
+ removeTempDir(appDir);
1093
1211
  if (code === 0) {
1094
1212
  chmodSync(opts.outputPath, 493);
1095
1213
  resolve({ success: true, outputPath: opts.outputPath });
@@ -1098,10 +1216,12 @@ Icon=${binaryName}
1098
1216
  }
1099
1217
  });
1100
1218
  proc.on("error", (err) => {
1101
- rmSync(appDir, { recursive: true, force: true });
1219
+ removeTempDir(appDir);
1102
1220
  resolve({ success: false, error: `appimagetool not found: ${err.message}` });
1103
1221
  });
1104
1222
  } catch (error) {
1223
+ if (staging)
1224
+ removeTempDir(staging);
1105
1225
  resolve({ success: false, error: error.message });
1106
1226
  }
1107
1227
  });
@@ -1124,6 +1244,7 @@ async function pack(options) {
1124
1244
  }
1125
1245
  var DEFAULT_DEB_DEPENDENCIES, CRC32_TABLE, URL_SCHEME, MEBIBYTE, HDIUTIL_MAX_ATTEMPTS = 3, runHdiutil = (args) => runTool("hdiutil", args), WINDOWS_NOTIFICATION_ID_FILE = "craft-notification-id.txt";
1126
1246
  var init_package = __esm(() => {
1247
+ init_temp_dir();
1127
1248
  DEFAULT_DEB_DEPENDENCIES = ["libgtk-3-0", "libwebkit2gtk-4.1-37", "libnotify-bin"];
1128
1249
  CRC32_TABLE = (() => {
1129
1250
  const table = new Uint32Array(256);
@@ -3223,7 +3344,7 @@ var prefix = getPrefix();
3223
3344
 
3224
3345
  // bin/cli.ts
3225
3346
  import { spawn as spawn2 } from "child_process";
3226
- import { existsSync as existsSync4 } from "fs";
3347
+ import { existsSync as existsSync5 } from "fs";
3227
3348
  import process6 from "process";
3228
3349
 
3229
3350
  // src/binary-resolver.ts
@@ -3303,7 +3424,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
3303
3424
  `);
3304
3425
  }
3305
3426
  // package.json
3306
- var version = "0.0.186";
3427
+ var version = "0.0.187";
3307
3428
 
3308
3429
  // bin/cli.ts
3309
3430
  var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
@@ -3417,7 +3538,7 @@ cli.command("build", "Build the Craft application").option("--release", "Build i
3417
3538
  console.log(`Platforms: ${platforms.join(", ")}`);
3418
3539
  console.log(`Mode: ${options?.release ? "Release" : "Debug"}
3419
3540
  `);
3420
- const { existsSync: existsSync5 } = await import("fs");
3541
+ const { existsSync: existsSync6 } = await import("fs");
3421
3542
  const { spawn: spawn3 } = await import("child_process");
3422
3543
  for (const platform of platforms) {
3423
3544
  console.log(`\uD83D\uDCE6 Building for ${platform}...`);
@@ -3428,7 +3549,7 @@ cli.command("build", "Build the Craft application").option("--release", "Build i
3428
3549
  continue;
3429
3550
  }
3430
3551
  const iosDir = "./ios";
3431
- if (existsSync5(iosDir)) {
3552
+ if (existsSync6(iosDir)) {
3432
3553
  const buildType = options?.release ? "Release" : "Debug";
3433
3554
  await new Promise((resolve, reject) => {
3434
3555
  const proc = spawn3("xcodebuild", [
@@ -3451,7 +3572,7 @@ cli.command("build", "Build the Craft application").option("--release", "Build i
3451
3572
  }
3452
3573
  } else if (platform === "android") {
3453
3574
  const androidDir = "./android";
3454
- if (existsSync5(androidDir)) {
3575
+ if (existsSync6(androidDir)) {
3455
3576
  const task = options?.release ? "assembleRelease" : "assembleDebug";
3456
3577
  await new Promise((resolve, reject) => {
3457
3578
  const proc = spawn3("./gradlew", [task], {
@@ -3466,7 +3587,7 @@ cli.command("build", "Build the Craft application").option("--release", "Build i
3466
3587
  console.log(` \u26A0\uFE0F No Android project found. Run: craft android init`);
3467
3588
  }
3468
3589
  } else if (platform === "macos" || platform === "windows" || platform === "linux") {
3469
- const zigDir = existsSync5("./packages/zig") ? "./packages/zig" : ".";
3590
+ const zigDir = existsSync6("./packages/zig") ? "./packages/zig" : ".";
3470
3591
  const optimizeFlag = options?.release ? "-Doptimize=ReleaseSafe" : "";
3471
3592
  await new Promise((resolve, reject) => {
3472
3593
  const args = ["build"];
@@ -3515,7 +3636,7 @@ cli.command("package", "Create installers for your Craft application").option("-
3515
3636
  const { packageApp: packageApp2 } = packageModule;
3516
3637
  let config;
3517
3638
  if (options?.config) {
3518
- if (!existsSync4(options.config)) {
3639
+ if (!existsSync5(options.config)) {
3519
3640
  console.error(`\u274C Config file not found: ${options.config}`);
3520
3641
  process6.exit(1);
3521
3642
  }
@@ -3724,15 +3845,15 @@ cli.command("preview [path]", "Preview app in browser before building native").o
3724
3845
  });
3725
3846
  });
3726
3847
  cli.command("publish", "Publish app to App Store or Play Store").option("--ios", "Publish to App Store (TestFlight)").option("--android", "Publish to Play Store").option("--api-key <path>", "App Store Connect API key path").option("--service-account <path>", "Google Play service account JSON").option("-o, --output <dir>", "Project directory", { default: "." }).example("craft publish --ios").example("craft publish --android").action(async (options) => {
3727
- const { existsSync: existsSync5 } = await import("fs");
3728
- const { join: join2 } = await import("path");
3848
+ const { existsSync: existsSync6 } = await import("fs");
3849
+ const { join: join3 } = await import("path");
3729
3850
  const { $ } = await Promise.resolve(globalThis.Bun);
3730
3851
  if (options?.ios) {
3731
3852
  console.log(`
3732
3853
  \uD83D\uDCF1 Publishing to App Store (TestFlight)...
3733
3854
  `);
3734
- const iosDir = join2(options?.output || ".", "ios");
3735
- if (!existsSync5(iosDir)) {
3855
+ const iosDir = join3(options?.output || ".", "ios");
3856
+ if (!existsSync6(iosDir)) {
3736
3857
  console.error("\u274C No iOS project found. Run: craft ios init");
3737
3858
  process6.exit(1);
3738
3859
  }
@@ -3761,8 +3882,8 @@ cli.command("publish", "Publish app to App Store or Play Store").option("--ios",
3761
3882
  console.log(`
3762
3883
  \uD83E\uDD16 Publishing to Play Store...
3763
3884
  `);
3764
- const androidDir = join2(options?.output || ".", "android");
3765
- if (!existsSync5(androidDir)) {
3885
+ const androidDir = join3(options?.output || ".", "android");
3886
+ if (!existsSync6(androidDir)) {
3766
3887
  console.error("\u274C No Android project found. Run: craft android init");
3767
3888
  process6.exit(1);
3768
3889
  }
@@ -3770,7 +3891,7 @@ cli.command("publish", "Publish app to App Store or Play Store").option("--ios",
3770
3891
  try {
3771
3892
  await $`cd ${androidDir} && ./gradlew bundleRelease`;
3772
3893
  console.log("\u2705 AAB created");
3773
- const aabPath = join2(androidDir, "app/build/outputs/bundle/release/app-release.aab");
3894
+ const aabPath = join3(androidDir, "app/build/outputs/bundle/release/app-release.aab");
3774
3895
  if (options?.serviceAccount) {
3775
3896
  console.log("2. Uploading to Play Store...");
3776
3897
  console.log("\u26A0\uFE0F Automatic Play Store upload requires fastlane or Google Play API integration.");
@@ -3809,31 +3930,31 @@ cli.command("init <name>", "Initialize a new Craft project").option("--template
3809
3930
  `);
3810
3931
  const bundleId = options?.bundleId || `com.example.${name.toLowerCase().replace(/[^a-z0-9]/g, "")}`;
3811
3932
  const appNameSlug = name.toLowerCase().replace(/[^a-z0-9]/g, "-");
3812
- const { mkdirSync: mkdirSync2, writeFileSync: writeFileSync3, existsSync: existsSync5, readdirSync: readdirSync2, readFileSync: readFileSync3, cpSync: cpSync2 } = await import("fs");
3813
- const { join: join2, dirname } = await import("path");
3933
+ const { mkdirSync: mkdirSync2, writeFileSync: writeFileSync4, existsSync: existsSync6, readdirSync: readdirSync3, readFileSync: readFileSync3, cpSync: cpSync2 } = await import("fs");
3934
+ const { join: join3, dirname } = await import("path");
3814
3935
  const replaceVars = (content) => {
3815
3936
  return content.replace(/\{\{APP_NAME\}\}/g, name).replace(/\{\{APP_NAME_SLUG\}\}/g, appNameSlug).replace(/\{\{BUNDLE_ID\}\}/g, bundleId).replace(/\{\{AUTHOR\}\}/g, "Developer");
3816
3937
  };
3817
3938
  const copyTemplate = async (templateName, destDir) => {
3818
- const templateDir = join2(import.meta.dir, "templates/projects", templateName);
3819
- if (!existsSync5(templateDir)) {
3939
+ const templateDir = join3(import.meta.dir, "templates/projects", templateName);
3940
+ if (!existsSync6(templateDir)) {
3820
3941
  console.log(` \u26A0\uFE0F Template '${templateName}' not found, using blank template`);
3821
3942
  return false;
3822
3943
  }
3823
3944
  const copyRecursive = (src, dest) => {
3824
- if (!existsSync5(dest)) {
3945
+ if (!existsSync6(dest)) {
3825
3946
  mkdirSync2(dest, { recursive: true });
3826
3947
  }
3827
- const entries = readdirSync2(src, { withFileTypes: true });
3948
+ const entries = readdirSync3(src, { withFileTypes: true });
3828
3949
  for (const entry of entries) {
3829
- const srcPath = join2(src, entry.name);
3830
- const destPath = join2(dest, entry.name);
3950
+ const srcPath = join3(src, entry.name);
3951
+ const destPath = join3(dest, entry.name);
3831
3952
  if (entry.isDirectory()) {
3832
3953
  copyRecursive(srcPath, destPath);
3833
3954
  } else {
3834
3955
  const content = readFileSync3(srcPath, "utf-8");
3835
3956
  const processedContent = replaceVars(content);
3836
- writeFileSync3(destPath, processedContent);
3957
+ writeFileSync4(destPath, processedContent);
3837
3958
  }
3838
3959
  }
3839
3960
  };
@@ -3842,13 +3963,13 @@ cli.command("init <name>", "Initialize a new Craft project").option("--template
3842
3963
  };
3843
3964
  if (["blank", "tabs", "drawer", "dashboard"].includes(template)) {
3844
3965
  console.log(`\uD83D\uDCC1 Creating ${template} project from template...`);
3845
- if (!existsSync5(name)) {
3966
+ if (!existsSync6(name)) {
3846
3967
  mkdirSync2(name, { recursive: true });
3847
3968
  }
3848
3969
  const copied = await copyTemplate(template, name);
3849
3970
  if (!copied) {
3850
- mkdirSync2(join2(name, "src"), { recursive: true });
3851
- writeFileSync3(join2(name, "index.html"), replaceVars(`<!DOCTYPE html>
3971
+ mkdirSync2(join3(name, "src"), { recursive: true });
3972
+ writeFileSync4(join3(name, "index.html"), replaceVars(`<!DOCTYPE html>
3852
3973
  <html lang="en">
3853
3974
  <head>
3854
3975
  <meta charset="UTF-8">
@@ -3862,7 +3983,7 @@ cli.command("init <name>", "Initialize a new Craft project").option("--template
3862
3983
  </div>
3863
3984
  </body>
3864
3985
  </html>`));
3865
- writeFileSync3(join2(name, "package.json"), replaceVars(JSON.stringify({
3986
+ writeFileSync4(join3(name, "package.json"), replaceVars(JSON.stringify({
3866
3987
  name: "{{APP_NAME_SLUG}}",
3867
3988
  version: "1.0.0",
3868
3989
  private: true,
@@ -3876,12 +3997,12 @@ cli.command("init <name>", "Initialize a new Craft project").option("--template
3876
3997
  }
3877
3998
  }, null, 2)));
3878
3999
  }
3879
- pinCraftNativeDependency(join2(name, "package.json"), version);
4000
+ pinCraftNativeDependency(join3(name, "package.json"), version);
3880
4001
  console.log(`\u2705 ${template} project created`);
3881
4002
  }
3882
4003
  if (template === "desktop" || template === "all") {
3883
4004
  console.log("\uD83D\uDCC1 Creating desktop project structure...");
3884
- if (!existsSync5(name)) {
4005
+ if (!existsSync6(name)) {
3885
4006
  mkdirSync2(name, { recursive: true });
3886
4007
  }
3887
4008
  const configContent = `import type { CraftConfig } from 'craft-native'
@@ -3896,7 +4017,7 @@ export default {
3896
4017
  },
3897
4018
  } satisfies CraftConfig
3898
4019
  `;
3899
- writeFileSync3(`${name}/craft.config.ts`, configContent);
4020
+ writeFileSync4(`${name}/craft.config.ts`, configContent);
3900
4021
  const htmlContent = `<!DOCTYPE html>
3901
4022
  <html lang="en">
3902
4023
  <head>
@@ -3927,7 +4048,7 @@ export default {
3927
4048
  </body>
3928
4049
  </html>
3929
4050
  `;
3930
- writeFileSync3(`${name}/index.html`, htmlContent);
4051
+ writeFileSync4(`${name}/index.html`, htmlContent);
3931
4052
  const packageJson = {
3932
4053
  name: appNameSlug,
3933
4054
  version: "0.1.0",
@@ -3943,7 +4064,7 @@ export default {
3943
4064
  "craft-native": `^${version}`
3944
4065
  }
3945
4066
  };
3946
- writeFileSync3(`${name}/package.json`, JSON.stringify(packageJson, null, 2));
4067
+ writeFileSync4(`${name}/package.json`, JSON.stringify(packageJson, null, 2));
3947
4068
  pinCraftNativeDependency(`${name}/package.json`, version);
3948
4069
  console.log("\u2705 Desktop project created");
3949
4070
  }