craft-native 0.0.186 → 0.0.189
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/android/templates/CraftNative.kt.template +34 -0
- package/dist/android/templates/CraftNativeCapabilities.kt.template +92 -9
- package/dist/android/templates/CraftNativeShell.kt.template +14 -2
- package/dist/android/templates/MainActivityNative.kt.template +312 -24
- package/dist/browser/dialogs.d.ts +20 -0
- package/dist/browser/storage.d.ts +31 -0
- package/dist/browser.d.ts +22 -0
- package/dist/browser.js +705 -0
- 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/CraftHybrid.swift +36 -4
- package/dist/ios/templates/CraftNativeActions.swift +16 -4
- package/dist/ios/templates/CraftNativeFiles.swift +131 -25
- package/dist/ios/templates/CraftNativeScreen.swift +454 -3
- package/dist/macos/templates/native_layout.zig +299 -6
- package/dist/temp-dir.d.ts +65 -0
- package/package.json +9 -1
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
|
|
164
|
+
existsSync as existsSync4,
|
|
52
165
|
lstatSync,
|
|
53
166
|
mkdirSync,
|
|
54
|
-
mkdtempSync,
|
|
55
167
|
readFileSync as readFileSync2,
|
|
56
|
-
readdirSync,
|
|
57
|
-
rmSync,
|
|
58
|
-
writeFileSync as
|
|
168
|
+
readdirSync as readdirSync2,
|
|
169
|
+
rmSync as rmSync2,
|
|
170
|
+
writeFileSync as writeFileSync3
|
|
59
171
|
} from "fs";
|
|
60
|
-
import { homedir
|
|
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 || !
|
|
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 ||
|
|
140
|
-
if (!
|
|
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 =
|
|
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 =
|
|
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 =
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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:
|
|
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 =
|
|
508
|
-
const macOS =
|
|
619
|
+
const contents = join2(outputPath, "Contents");
|
|
620
|
+
const macOS = join2(contents, "MacOS");
|
|
509
621
|
mkdirSync(macOS, { recursive: true });
|
|
510
|
-
mkdirSync(
|
|
511
|
-
copyFileSync(binaryPath,
|
|
512
|
-
chmodSync(
|
|
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 (!
|
|
626
|
+
if (!existsSync4(executable))
|
|
515
627
|
return { success: false, error: `Additional executable not found: ${executable}` };
|
|
516
|
-
const destination =
|
|
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 (!
|
|
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,
|
|
637
|
+
copyFileSync(iconPath, join2(contents, "Resources", `${iconName}.icns`));
|
|
526
638
|
}
|
|
527
639
|
if (provisioningProfile) {
|
|
528
|
-
if (!
|
|
640
|
+
if (!existsSync4(provisioningProfile))
|
|
529
641
|
return { success: false, error: `Provisioning profile not found: ${provisioningProfile}` };
|
|
530
|
-
copyFileSync(provisioningProfile,
|
|
642
|
+
copyFileSync(provisioningProfile, join2(contents, "embedded.provisionprofile"));
|
|
531
643
|
}
|
|
532
|
-
|
|
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
|
|
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
|
-
|
|
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 =
|
|
773
|
+
const tempDir = createTempDir("craft-pkg-");
|
|
662
774
|
try {
|
|
663
|
-
const root =
|
|
664
|
-
const appsDir =
|
|
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,
|
|
669
|
-
const componentPlistPath =
|
|
670
|
-
|
|
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
|
-
|
|
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 (!
|
|
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 =
|
|
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 =
|
|
805
|
-
const wxsPath =
|
|
806
|
-
const wixobjPath =
|
|
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
|
-
|
|
920
|
+
writeFileSync3(join2(tempDir, WINDOWS_NOTIFICATION_ID_FILE), windowsNotificationAppId(opts.name, opts.manufacturer));
|
|
809
921
|
for (const file of additionalFiles)
|
|
810
|
-
copyFileSync(file.path,
|
|
811
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
871
|
-
|
|
872
|
-
const
|
|
873
|
-
const
|
|
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,
|
|
879
|
-
chmodSync(
|
|
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
|
-
|
|
890
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
913
|
-
const specDir =
|
|
914
|
-
const sourcesDir =
|
|
915
|
-
const buildDir =
|
|
916
|
-
const rpmsDir =
|
|
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,
|
|
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 =
|
|
959
|
-
|
|
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 =
|
|
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 =
|
|
987
|
-
|
|
988
|
-
const
|
|
989
|
-
const
|
|
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,
|
|
994
|
-
chmodSync(
|
|
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
|
-
|
|
1002
|
-
chmodSync(
|
|
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
|
-
|
|
1012
|
-
if (opts.iconPath &&
|
|
1013
|
-
copyFileSync(opts.iconPath,
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
3427
|
+
var version = "0.0.189";
|
|
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:
|
|
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 (
|
|
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 (
|
|
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 =
|
|
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 (!
|
|
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:
|
|
3728
|
-
const { join:
|
|
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 =
|
|
3735
|
-
if (!
|
|
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 =
|
|
3765
|
-
if (!
|
|
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 =
|
|
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:
|
|
3813
|
-
const { join:
|
|
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 =
|
|
3819
|
-
if (!
|
|
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 (!
|
|
3945
|
+
if (!existsSync6(dest)) {
|
|
3825
3946
|
mkdirSync2(dest, { recursive: true });
|
|
3826
3947
|
}
|
|
3827
|
-
const entries =
|
|
3948
|
+
const entries = readdirSync3(src, { withFileTypes: true });
|
|
3828
3949
|
for (const entry of entries) {
|
|
3829
|
-
const srcPath =
|
|
3830
|
-
const destPath =
|
|
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
|
-
|
|
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 (!
|
|
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(
|
|
3851
|
-
|
|
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
|
-
|
|
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(
|
|
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 (!
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
}
|