craft-native 0.0.436 → 0.0.442
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/LICENSE.md +30 -0
- package/README.md +35 -0
- package/dist/android/src/index.d.ts +8 -0
- package/dist/android/src/index.js +17 -2
- package/dist/android/templates/CraftHealthServices.kt.template +2 -0
- package/dist/android/templates/CraftNativeCapabilities.kt.template +42 -1
- package/dist/android/templates/CraftNativeMotion.kt.template +269 -0
- package/dist/android/templates/CraftNativeServices.kt.template +6 -1
- package/dist/android/templates/CraftPassiveSteps.kt.template +159 -0
- package/dist/android/templates/CraftRecordingPressure.kt.template +156 -0
- package/dist/android/templates/LocationRecordingService.kt.template +77 -9
- package/dist/android/templates/MainActivityNative.kt.template +129 -1
- package/dist/cli.js +289 -108
- package/dist/components/index.d.ts +25 -0
- package/dist/index.cjs +207 -27
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +321 -140
- package/dist/installer-background.d.ts +2 -0
- package/dist/installer-layout.d.ts +1 -0
- package/dist/ios/src/index.d.ts +10 -0
- package/dist/ios/src/index.js +28 -2
- package/dist/ios/templates/CraftApp.swift +14 -0
- package/dist/ios/templates/CraftHealth.swift +2 -1
- package/dist/ios/templates/CraftHealthBackground.swift +308 -0
- package/dist/ios/templates/CraftNativeActions.swift +153 -0
- package/dist/ios/templates/CraftNativePedometer.swift +181 -0
- package/dist/ios/templates/CraftNativeScreen.swift +76 -0
- package/dist/macos/src/index.js +1 -1
- package/dist/macos/src/toolchain.d.ts +1 -1
- package/dist/macos/templates/CraftMacApplication.swift +124 -39
- package/dist/macos/templates/CraftMacRenderer.swift +111 -33
- package/dist/macos/templates/CraftMacRuntime.swift +270 -81
- package/dist/package.d.ts +40 -0
- package/dist/types.d.ts +26 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -12,10 +12,140 @@ var __esm = (fn, res, err) => () => {
|
|
|
12
12
|
return res;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
// src/installer-layout.ts
|
|
16
|
+
import { execFileSync } from "child_process";
|
|
17
|
+
import { statSync, writeFileSync as writeFileSync2 } from "fs";
|
|
18
|
+
import { join } from "path";
|
|
19
|
+
function backgroundAlias(mount, volume) {
|
|
20
|
+
const folder = ".background";
|
|
21
|
+
const filename = "installer.png";
|
|
22
|
+
const directory = statSync(join(mount, folder));
|
|
23
|
+
const file = statSync(join(mount, folder, filename));
|
|
24
|
+
const date = (ms) => Math.floor(ms / 1000) + 2082844800;
|
|
25
|
+
const volumeDate = date(statSync(mount).birthtimeMs);
|
|
26
|
+
const fileDate = date(file.birthtimeMs);
|
|
27
|
+
const preciseDate = (value) => {
|
|
28
|
+
const out = Buffer.alloc(8);
|
|
29
|
+
out.writeBigUInt64BE(BigInt(value) * 65536n);
|
|
30
|
+
return out;
|
|
31
|
+
};
|
|
32
|
+
const body = Buffer.concat([
|
|
33
|
+
number(0, 2),
|
|
34
|
+
pascal(volume, 28),
|
|
35
|
+
number(volumeDate),
|
|
36
|
+
Buffer.from("H+"),
|
|
37
|
+
number(0, 2),
|
|
38
|
+
number(directory.ino),
|
|
39
|
+
pascal(filename, 64),
|
|
40
|
+
number(file.ino),
|
|
41
|
+
number(fileDate),
|
|
42
|
+
Buffer.alloc(8),
|
|
43
|
+
number(65535, 2),
|
|
44
|
+
number(65535, 2),
|
|
45
|
+
Buffer.alloc(16),
|
|
46
|
+
tag(0, Buffer.from(folder)),
|
|
47
|
+
tag(16, preciseDate(volumeDate)),
|
|
48
|
+
tag(17, preciseDate(fileDate)),
|
|
49
|
+
tag(1, number(directory.ino)),
|
|
50
|
+
tag(2, Buffer.from(`${volume}:${folder}:\x00${filename}`)),
|
|
51
|
+
tag(14, Buffer.concat([number(filename.length, 2), unicode2(filename)])),
|
|
52
|
+
tag(15, Buffer.concat([number(volume.length, 2), unicode2(volume)])),
|
|
53
|
+
tag(18, Buffer.from(`/${folder}/${filename}`)),
|
|
54
|
+
tag(19, Buffer.from(`/Volumes/${volume}`)),
|
|
55
|
+
number(65535, 2),
|
|
56
|
+
number(0, 2)
|
|
57
|
+
]);
|
|
58
|
+
return Buffer.concat([Buffer.alloc(4), number(body.length + 8, 2), number(2, 2), body]);
|
|
59
|
+
}
|
|
60
|
+
function plist(values) {
|
|
61
|
+
const escape = (value) => value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">");
|
|
62
|
+
const entries = Object.entries(values).map(([key, value]) => {
|
|
63
|
+
const data = Buffer.isBuffer(value) ? `<data>${value.toString("base64")}</data>` : typeof value === "boolean" ? `<${value}/>` : typeof value === "number" ? ["viewOptionsVersion", "backgroundType"].includes(key) ? `<integer>${value}</integer>` : `<real>${value}</real>` : `<string>${escape(value)}</string>`;
|
|
64
|
+
return `<key>${key}</key>${data}`;
|
|
65
|
+
}).join("");
|
|
66
|
+
return execFileSync("plutil", ["-convert", "binary1", "-o", "-", "-"], { input: `<?xml version="1.0"?><plist version="1.0"><dict>${entries}</dict></plist>` });
|
|
67
|
+
}
|
|
68
|
+
function writeInstallerLayout(mount, volume, appName) {
|
|
69
|
+
const records = [];
|
|
70
|
+
const blob = (name, code, data) => records.push({ name, code, type: "blob", data: Buffer.concat([number(data.length), data]) });
|
|
71
|
+
blob(".", "bwsp", plist({ ShowStatusBar: false, ShowToolbar: false, ShowTabView: false, ShowSidebar: false, ContainerShowSidebar: false, ShowPathbar: false, SidebarWidth: 0, PreviewPaneVisibility: false, WindowBounds: "{{100, 100}, {660, 460}}" }));
|
|
72
|
+
blob(".", "icvp", plist({ viewOptionsVersion: 1, backgroundType: 2, backgroundColorRed: 1, backgroundColorGreen: 1, backgroundColorBlue: 1, backgroundImageAlias: backgroundAlias(mount, volume), iconSize: 96, arrangeBy: "none", gridSpacing: 100, gridOffsetX: 0, gridOffsetY: 0, scrollPositionX: 0, scrollPositionY: 0, textSize: 13, labelOnBottom: true, showIconPreview: true, showItemInfo: false }));
|
|
73
|
+
records.push({ name: ".", code: "vSrn", type: "long", data: number(1) });
|
|
74
|
+
records.push({ name: ".", code: "icvl", type: "type", data: Buffer.from("icnv") });
|
|
75
|
+
records.push({ name: ".", code: "vstl", type: "type", data: Buffer.from("icnv") });
|
|
76
|
+
for (const [name, x, y] of [[appName, 160, 190], ["Applications", 500, 190], [".background", 500, 600]])
|
|
77
|
+
blob(name, "Iloc", Buffer.concat([number(x), number(y), Buffer.from("ffffffffffff0000", "hex")]));
|
|
78
|
+
records.sort((a, b) => {
|
|
79
|
+
const left = a.name.normalize("NFD").toLowerCase();
|
|
80
|
+
const right = b.name.normalize("NFD").toLowerCase();
|
|
81
|
+
return left < right ? -1 : left > right ? 1 : a.code < b.code ? -1 : 1;
|
|
82
|
+
});
|
|
83
|
+
const leaf = Buffer.concat([number(0), number(records.length), ...records.map((record) => {
|
|
84
|
+
const name = record.name.normalize("NFD");
|
|
85
|
+
return Buffer.concat([number(name.length), unicode2(name), Buffer.from(record.code + record.type), record.data]);
|
|
86
|
+
})]);
|
|
87
|
+
if (leaf.length > 4096)
|
|
88
|
+
throw new Error("Installer layout exceeds the Finder store leaf capacity");
|
|
89
|
+
const offsets = Buffer.alloc(1024);
|
|
90
|
+
offsets.writeUInt32BE(2048 | 11, 0);
|
|
91
|
+
offsets.writeUInt32BE(32 | 5, 4);
|
|
92
|
+
offsets.writeUInt32BE(4096 | 12, 8);
|
|
93
|
+
const free = Array.from({ length: 32 }, (_, power) => power >= 6 && power <= 10 || power >= 13 && power <= 30 ? Buffer.concat([number(1), number(2 ** power)]) : number(0));
|
|
94
|
+
const root = Buffer.concat([number(3), number(0), offsets, number(1), Buffer.from([4]), Buffer.from("DSDB"), number(1), ...free]);
|
|
95
|
+
const out = Buffer.alloc(8196);
|
|
96
|
+
Buffer.concat([number(1), Buffer.from("Bud1"), number(2048), number(root.length), number(2048), Buffer.alloc(16)]).copy(out);
|
|
97
|
+
Buffer.concat([number(2), number(0), number(records.length), number(1), number(4096)]).copy(out, 36);
|
|
98
|
+
root.copy(out, 2052);
|
|
99
|
+
leaf.copy(out, 4100);
|
|
100
|
+
writeFileSync2(join(mount, ".DS_Store"), out);
|
|
101
|
+
}
|
|
102
|
+
var number = (value, bytes = 4) => {
|
|
103
|
+
const out = Buffer.alloc(bytes);
|
|
104
|
+
out.writeUIntBE(value, 0, bytes);
|
|
105
|
+
return out;
|
|
106
|
+
}, unicode2 = (value) => Buffer.from(value, "utf16le").swap16(), pascal = (value, size) => {
|
|
107
|
+
const out = Buffer.alloc(size);
|
|
108
|
+
const bytes = Buffer.from(value).subarray(0, size - 1);
|
|
109
|
+
out[0] = bytes.length;
|
|
110
|
+
bytes.copy(out, 1);
|
|
111
|
+
return out;
|
|
112
|
+
}, tag = (id, data) => Buffer.concat([number(id, 2), number(data.length, 2), data, Buffer.alloc(data.length % 2)]);
|
|
113
|
+
var init_installer_layout = __esm(() => {
|
|
114
|
+
/*!
|
|
115
|
+
* Format implementation adapted from MIT-licensed references:
|
|
116
|
+
* Copyright (c) 2020 Kenty Gwend
|
|
117
|
+
* Copyright (c) 2026 John Campion Jr
|
|
118
|
+
* Copyright (c) 2014 Alastair Houghton
|
|
119
|
+
* Copyright (c) 2022 Russell Keith-Magee
|
|
120
|
+
*
|
|
121
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
122
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
123
|
+
* in the Software without restriction, including without limitation the rights
|
|
124
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
125
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
126
|
+
* furnished to do so, subject to the following conditions:
|
|
127
|
+
* The above copyright notice and this permission notice shall be included in
|
|
128
|
+
* all copies or substantial portions of the Software.
|
|
129
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
130
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
131
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
132
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
133
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
134
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
135
|
+
* SOFTWARE.
|
|
136
|
+
*/
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
// src/installer-background.ts
|
|
140
|
+
var installerBackground;
|
|
141
|
+
var init_installer_background = __esm(() => {
|
|
142
|
+
installerBackground = Buffer.from("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vpDh4twyyyyT7S6//PKDdsOXbt/xkT2miF0Kvq200kqZDVsFuI4P6667buZw9913p5deeilnMWGz3nrr5euIqtEURBYCiPFjn20ASyyxRO4TW1wPYQkXGLz44ovZD67hB8v0d955Z3rllVeyYAs/iEnZD2wg5LDx+OOPp9dffz33AcsNN9wwLb744pnpaHwn0/3GG29k34kpMV5yySXTWmutlV+won/en3zyyfTCCy/ksWIbP5577rnclnHgcxT8wxbbF2DL+JZaaqlsk72v2IQZBdvcp9ShEKsVV1xx8F58880309JLL53jsvLKK4/5/ZI79R8JSGDMCSgoxxypBiUwPgT+4z/+I++vZLI+7LDD8uT9v//7v1l4cA6BxaR/zDHH5Ad5YkJHXCFK/u///i/NmjUrixrEAAVxggA44ogj0he+8IUsAv7xH/8x70ukTgjRc889N51//vlp2sADNFynHYIDMYHda6+9dj677INEeH7xi19MhxxyyKAA7ZYUfSJQ/vu//zuPhTEeeOCB6fd///fT7Nmz01/+5V/m6wjaP/7jP07w4fx7772XRSSiZ9ddd00nnHBCFjVwG64gnB544IFBO4gzxCNMEUGbb755OvbYY9P06dOzEKL+jTfemLcLYBcRiG//8z//k+65557sB+IMUfe5z30u/eqv/moW9REreLN/8Qc/+EG68MILs4B9//33Mz9ELAL2q1/9am6L77AYqmALGz/60Y/ylwj2qVLof4UVVsgcyPQi8Fjiht2jjz6a+6ct5aSTTsovxsfyN+Om/R133JHjzpgQ0PiCeMUu2xF+5Vd+JY8L/+j3r//6r7Mwhd3v/u7v5rrf/e53s4BlfGRF+YL05S9/Od8v9D3c2LhukYAEektAQdlb/vYugY4JkBlj4mdSv+KKK7JIJLvDZ15MwGSCeEocIcPeQiZwMkN/9Vd/la666qo8kSNeED7UZzJHRCAWOEaoIprIpCF6EHAURAHXEWq0Q3CQJeQp7VtvvTXbw274gRglE8o+TAQHomssCwIx9vlF5os+OUfhOEQMPuEv74zjvPPOy6LpL/7iL/L4hhIuCKRbbrkl/emf/mkW7Qip4hgZF0L63nvvzXUQqvBCEOIHx/CHPSzCD3zBjx//+MeZ5R/90R9ln6P+3//932chSH36o198ZMxkW//sz/4sx+jQQw/NfeXG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6gzXR1zrxA7jHS7u2B5NnfCh3XsnfrWz4zkJSKA3BOZf/+mND/YqAQlIQAINIsCXCwQqr5HEdoOwOFQJ1JqAGcpah0/nJSABCdSHAFlM9nEeddRR+WeMEJM8BER20iIBCdSbgHso6x0/vZeABCRQOwI8xBN7QclWKihrF0IdlsCnCJih/BQST0hAAhKQQJUE4in4KvvQtgQkML4E3EM5vrztTQISkIAEJCABCUw4AgrKCRdSByQBCUhAAhKQgATGl4CCcnx525sEJCABCUhAAhKYcAQUlBMupA5IAhKQgAQkIAEJjC8BBeX48rY3CUhAAhKQgAQkMOEIKCgnXEgdkAQkIAEJSEACEhhfAgrK8eVtbxKQgAQkIAEJSGDCEVBQTriQOiAJSEACEpCABCQwvgQUlOPL294kIAEJSEACEpDAhCOgoJxwIXVAEpCABCQgAQlIYHwJKCjHl7e9SUACEpCABCQggQlHQEE54ULqgCTQGwKTJk1KkydPTrxbekOgyH+hhRbK8ajSk/Hoo0r/tS0BCYwdAQXl2LHUkgQqIYBAY+IuvhAOU6ZM6al4w58Qj7zPmTMnPfvss+mDDz6ohMN4Gy2Obyz6jviNha12Nj788MPM/7333stxeemll/LndnU7ORf3YbTl84svvjimfYRt3yUggfoRmFI/l/VYAs0hgHB86KGH0u23355Fwrx583LWaamllkprr712Wn/99bOw/Pjjj8cVCv29/vrrabHFFkuLLrpo9umJJ55IF1xwQTriiCOybx999NG4+jSWneE741t88cXTIosskuDeTYHXFVdckebOnZv22muvHLNu7JXbIlZfffXV9MMf/jDtu+++afPNN0/nnXdeeuONN9Lxxx+fx9HNGBCPCNX3338/ce9xXzKWc889N73zzjvpG9/4Rr4XuumjPCY/S0AC9SJghrJe8dLbhhFAKLz88svprrvuSm+99Vae0N9888105513ptNPPz395Cc/Se++++58mUImf0o5w8Z5hADn25XydT6HrWJ9bCBeTjnllHTvvfemqVOn5suIJrKTvIetdu2pHNeH8qXY33D1sRM2hrI5mjrF/hjfK6+8kk4++eT0wAMPDI4v6hT74Xikgr3nn38+3XzzzemWW25JzzzzzKcEJXbCFuPhFZ/D/kjjRMzBHzFMn5tttlmaMWNGWnjhhQcFMTaH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SEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJSEACEpCABCRQHQEFZXVstSwBCUhAAhKQgAQaQUBB2YgwO0gJ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", "base64");
|
|
143
|
+
});
|
|
144
|
+
|
|
15
145
|
// src/temp-dir.ts
|
|
16
|
-
import { existsSync as existsSync3, mkdtempSync, readdirSync, rmSync, statSync, writeFileSync as
|
|
146
|
+
import { existsSync as existsSync3, mkdtempSync, readdirSync, rmSync, statSync as statSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
17
147
|
import { constants as osConstants, tmpdir } from "os";
|
|
18
|
-
import { join } from "path";
|
|
148
|
+
import { join as join2 } from "path";
|
|
19
149
|
function removeQuietly(dir) {
|
|
20
150
|
try {
|
|
21
151
|
rmSync(dir, { recursive: true, force: true });
|
|
@@ -83,11 +213,11 @@ function sweepOrphanedTempDirs(options = {}) {
|
|
|
83
213
|
const pid = Number(match[1]);
|
|
84
214
|
if (pid === process.pid || isAlive(pid))
|
|
85
215
|
continue;
|
|
86
|
-
const path =
|
|
216
|
+
const path = join2(root, name);
|
|
87
217
|
try {
|
|
88
|
-
if (now -
|
|
218
|
+
if (now - statSync2(path).mtimeMs < minAge)
|
|
89
219
|
continue;
|
|
90
|
-
if (existsSync3(
|
|
220
|
+
if (existsSync3(join2(path, KEEP_MARKER)))
|
|
91
221
|
continue;
|
|
92
222
|
} catch {
|
|
93
223
|
continue;
|
|
@@ -107,7 +237,7 @@ function createTempDir(label, root = tmpdir()) {
|
|
|
107
237
|
sweepOrphanedTempDirs({ root });
|
|
108
238
|
}
|
|
109
239
|
hook();
|
|
110
|
-
const dir = mkdtempSync(
|
|
240
|
+
const dir = mkdtempSync(join2(root, tempDirPrefix(label)));
|
|
111
241
|
live.add(dir);
|
|
112
242
|
return dir;
|
|
113
243
|
}
|
|
@@ -141,10 +271,11 @@ import {
|
|
|
141
271
|
readSync,
|
|
142
272
|
readdirSync as readdirSync2,
|
|
143
273
|
rmSync as rmSync2,
|
|
144
|
-
|
|
274
|
+
symlinkSync,
|
|
275
|
+
writeFileSync as writeFileSync4
|
|
145
276
|
} from "fs";
|
|
146
277
|
import { homedir } from "os";
|
|
147
|
-
import { basename, dirname, join as
|
|
278
|
+
import { basename, dirname, join as join3, resolve } from "path";
|
|
148
279
|
import { deflateRawSync } from "zlib";
|
|
149
280
|
function crc32(data) {
|
|
150
281
|
let c = 4294967295;
|
|
@@ -222,7 +353,7 @@ async function packageApp(config) {
|
|
|
222
353
|
throw new Error(`Binary not found: ${config.binaryPath}`);
|
|
223
354
|
}
|
|
224
355
|
const platforms = config.platforms || [detectPlatform()];
|
|
225
|
-
const outDir = config.outDir ||
|
|
356
|
+
const outDir = config.outDir || join3(process.cwd(), "dist");
|
|
226
357
|
if (!existsSync4(outDir)) {
|
|
227
358
|
mkdirSync(outDir, { recursive: true });
|
|
228
359
|
}
|
|
@@ -244,7 +375,7 @@ async function packageApp(config) {
|
|
|
244
375
|
function macOSAppStoreRuntimePath(providerPath) {
|
|
245
376
|
const providerName = basename(providerPath);
|
|
246
377
|
const storeName = providerName.startsWith("craft-webview") ? "craft-webview-app-store" : "craft-app-store";
|
|
247
|
-
const runtime = providerName === storeName ? providerPath :
|
|
378
|
+
const runtime = providerName === storeName ? providerPath : join3(dirname(providerPath), storeName);
|
|
248
379
|
if (!existsSync4(runtime))
|
|
249
380
|
throw new Error("App Store packaging requires Pantry\u2019s craft-app-store runtime. Upgrade Craft with Pantry before building.");
|
|
250
381
|
const bytes = readFileSync2(runtime);
|
|
@@ -271,7 +402,7 @@ async function packageMacOS(config, outDir) {
|
|
|
271
402
|
return [{ success: false, platform: "macos", format: "app", error: error.message }];
|
|
272
403
|
}
|
|
273
404
|
}
|
|
274
|
-
const appBundlePath =
|
|
405
|
+
const appBundlePath = join3(outDir, `${name}.app`);
|
|
275
406
|
const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
|
|
276
407
|
name,
|
|
277
408
|
version,
|
|
@@ -300,25 +431,25 @@ async function packageMacOS(config, outDir) {
|
|
|
300
431
|
return results;
|
|
301
432
|
}
|
|
302
433
|
try {
|
|
303
|
-
const contents =
|
|
304
|
-
if (opts.appStore && opts.appBundlePath && existsSync4(
|
|
434
|
+
const contents = join3(appBundlePath, "Contents");
|
|
435
|
+
if (opts.appStore && opts.appBundlePath && existsSync4(join3(contents, "Resources", "craft.json"))) {
|
|
305
436
|
if (!nativeRuntimePath)
|
|
306
437
|
throw new Error("App Store packaging of a prebuilt Craft bundle requires macos.nativeRuntimePath from Pantry.");
|
|
307
|
-
const plist =
|
|
438
|
+
const plist = join3(contents, "Info.plist");
|
|
308
439
|
const executable = spawnSync("plutil", ["-extract", "CFBundleExecutable", "raw", "-o", "-", plist], { encoding: "utf8" });
|
|
309
440
|
const name = executable.stdout.trim();
|
|
310
441
|
if (executable.status !== 0 || !name || basename(name) !== name || name === "." || name === "..")
|
|
311
442
|
throw new Error("Prebuilt Craft bundle has an invalid CFBundleExecutable");
|
|
312
|
-
copyFileSync(nativeRuntimePath,
|
|
313
|
-
chmodSync(
|
|
443
|
+
copyFileSync(nativeRuntimePath, join3(contents, "MacOS", name));
|
|
444
|
+
chmodSync(join3(contents, "MacOS", name), 493);
|
|
314
445
|
}
|
|
315
446
|
if (opts.provisioningProfile) {
|
|
316
|
-
const profile =
|
|
447
|
+
const profile = join3(contents, "embedded.provisionprofile");
|
|
317
448
|
copyFileSync(opts.provisioningProfile, profile);
|
|
318
449
|
chmodSync(profile, 420);
|
|
319
450
|
}
|
|
320
451
|
if (opts.privacyManifest)
|
|
321
|
-
copyFileSync(opts.privacyManifest,
|
|
452
|
+
copyFileSync(opts.privacyManifest, join3(contents, "Resources", "PrivacyInfo.xcprivacy"));
|
|
322
453
|
if (opts.appBundlePath) {
|
|
323
454
|
const metadata = {
|
|
324
455
|
CFBundleVersion: opts.buildNumber,
|
|
@@ -328,13 +459,13 @@ async function packageMacOS(config, outDir) {
|
|
|
328
459
|
};
|
|
329
460
|
if (config.iconPath) {
|
|
330
461
|
const icon = basename(config.iconPath);
|
|
331
|
-
copyFileSync(config.iconPath,
|
|
462
|
+
copyFileSync(config.iconPath, join3(contents, "Resources", icon));
|
|
332
463
|
metadata.CFBundleIconFile = icon;
|
|
333
464
|
}
|
|
334
465
|
for (const [key, value] of Object.entries(metadata)) {
|
|
335
466
|
if (value === undefined)
|
|
336
467
|
continue;
|
|
337
|
-
const result = await runTool("plutil", ["-replace", key, typeof value === "boolean" ? "-bool" : "-string", String(value),
|
|
468
|
+
const result = await runTool("plutil", ["-replace", key, typeof value === "boolean" ? "-bool" : "-string", String(value), join3(contents, "Info.plist")]);
|
|
338
469
|
if (!result.success)
|
|
339
470
|
throw new Error(result.error);
|
|
340
471
|
}
|
|
@@ -355,8 +486,8 @@ async function packageMacOS(config, outDir) {
|
|
|
355
486
|
}
|
|
356
487
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
357
488
|
if (opts.dmg !== false) {
|
|
358
|
-
const outputPath =
|
|
359
|
-
let dmgResult = await
|
|
489
|
+
const outputPath = join3(outDir, `${name}-${version}.dmg`);
|
|
490
|
+
let dmgResult = await createDiskImage({ appBundlePath, outputPath, volumeName: name });
|
|
360
491
|
if (dmgResult.success && opts.signIdentity) {
|
|
361
492
|
const signed = await runTool("codesign", codesignArguments({
|
|
362
493
|
path: outputPath,
|
|
@@ -380,7 +511,7 @@ async function packageMacOS(config, outDir) {
|
|
|
380
511
|
results.push(...await notarizeIfRequested(opts, outputPath, "dmg"));
|
|
381
512
|
}
|
|
382
513
|
if (opts.pkg || opts.appStore) {
|
|
383
|
-
const outputPath =
|
|
514
|
+
const outputPath = join3(outDir, `${name}-${version}.pkg`);
|
|
384
515
|
const pkgResult = await createPKG({
|
|
385
516
|
appBundlePath,
|
|
386
517
|
outputPath,
|
|
@@ -415,7 +546,7 @@ async function notarizeIfRequested(opts, artifactPath, format) {
|
|
|
415
546
|
}
|
|
416
547
|
const scratch = format === "app" ? createTempDir("craft-notarize-") : undefined;
|
|
417
548
|
try {
|
|
418
|
-
const submission = scratch ?
|
|
549
|
+
const submission = scratch ? join3(scratch, "app.zip") : artifactPath;
|
|
419
550
|
if (scratch) {
|
|
420
551
|
const zipped = await runTool("ditto", ["-c", "-k", "--keepParent", artifactPath, submission]);
|
|
421
552
|
if (!zipped.success)
|
|
@@ -453,7 +584,7 @@ async function packageWindows(config, outDir) {
|
|
|
453
584
|
name,
|
|
454
585
|
version,
|
|
455
586
|
binaryPath: config.binaryPath,
|
|
456
|
-
outputPath:
|
|
587
|
+
outputPath: join3(outDir, `${name}-${version}.msi`),
|
|
457
588
|
manufacturer: config.author || "Unknown",
|
|
458
589
|
architecture: opts.architecture || windowsArchitecture(process.arch),
|
|
459
590
|
additionalFiles: opts.additionalFiles,
|
|
@@ -477,7 +608,7 @@ async function packageWindows(config, outDir) {
|
|
|
477
608
|
manufacturer: config.author || "Unknown",
|
|
478
609
|
binaryPath: config.binaryPath,
|
|
479
610
|
additionalFiles: opts.additionalFiles,
|
|
480
|
-
outputPath:
|
|
611
|
+
outputPath: join3(outDir, `${name}-${version}-windows.zip`)
|
|
481
612
|
});
|
|
482
613
|
results.push({
|
|
483
614
|
success: zipResult.success,
|
|
@@ -498,7 +629,7 @@ async function packageLinux(config, outDir) {
|
|
|
498
629
|
name,
|
|
499
630
|
version,
|
|
500
631
|
binaryPath: config.binaryPath,
|
|
501
|
-
outputPath:
|
|
632
|
+
outputPath: join3(outDir, `${name}_${version}_amd64.deb`),
|
|
502
633
|
description: config.description || "",
|
|
503
634
|
maintainer: config.author || "Unknown",
|
|
504
635
|
dependencies: opts.debDependencies || [...DEFAULT_DEB_DEPENDENCIES],
|
|
@@ -518,7 +649,7 @@ async function packageLinux(config, outDir) {
|
|
|
518
649
|
name,
|
|
519
650
|
version,
|
|
520
651
|
binaryPath: config.binaryPath,
|
|
521
|
-
outputPath:
|
|
652
|
+
outputPath: join3(outDir, `${name}-${version}-1.x86_64.rpm`),
|
|
522
653
|
description: config.description || "",
|
|
523
654
|
requires: opts.rpmDependencies || ["gtk3", "webkit2gtk3"]
|
|
524
655
|
});
|
|
@@ -535,7 +666,7 @@ async function packageLinux(config, outDir) {
|
|
|
535
666
|
name,
|
|
536
667
|
version,
|
|
537
668
|
binaryPath: config.binaryPath,
|
|
538
|
-
outputPath:
|
|
669
|
+
outputPath: join3(outDir, `${name}-${version}-x86_64.AppImage`),
|
|
539
670
|
iconPath: config.iconPath
|
|
540
671
|
});
|
|
541
672
|
results.push({
|
|
@@ -645,13 +776,13 @@ async function signMacOSAppBundle(app, bundleId, opts, hardenedRuntime) {
|
|
|
645
776
|
try {
|
|
646
777
|
let helperEntitlements = opts.helperEntitlements;
|
|
647
778
|
if (opts.appStore && !helperEntitlements) {
|
|
648
|
-
helperEntitlements =
|
|
649
|
-
|
|
779
|
+
helperEntitlements = join3(scratch, "inherit.plist");
|
|
780
|
+
writeFileSync4(helperEntitlements, '<?xml version="1.0"?><plist version="1.0"><dict><key>com.apple.security.app-sandbox</key><true/><key>com.apple.security.inherit</key><true/></dict></plist>');
|
|
650
781
|
}
|
|
651
|
-
const extracted = await runTool("plutil", ["-extract", "CFBundleExecutable", "raw", "-o", "-",
|
|
782
|
+
const extracted = await runTool("plutil", ["-extract", "CFBundleExecutable", "raw", "-o", "-", join3(app, "Contents", "Info.plist")]);
|
|
652
783
|
if (!extracted.success)
|
|
653
784
|
throw new Error(extracted.error);
|
|
654
|
-
const main =
|
|
785
|
+
const main = join3(app, "Contents", "MacOS", extracted.stdout.trim());
|
|
655
786
|
const sign = async (path, entitlements, identifier) => {
|
|
656
787
|
const signed = await runTool("codesign", codesignArguments({ path, identity: opts.signIdentity, entitlements, hardenedRuntime, identifier, keychain: opts.signingKeychain, deep: false }));
|
|
657
788
|
if (!signed.success)
|
|
@@ -659,7 +790,7 @@ async function signMacOSAppBundle(app, bundleId, opts, hardenedRuntime) {
|
|
|
659
790
|
};
|
|
660
791
|
const walk = async (directory) => {
|
|
661
792
|
for (const entry of readdirSync2(directory)) {
|
|
662
|
-
const path =
|
|
793
|
+
const path = join3(directory, entry);
|
|
663
794
|
const stat = lstatSync(path);
|
|
664
795
|
if (stat.isSymbolicLink())
|
|
665
796
|
continue;
|
|
@@ -673,7 +804,7 @@ async function signMacOSAppBundle(app, bundleId, opts, hardenedRuntime) {
|
|
|
673
804
|
}
|
|
674
805
|
}
|
|
675
806
|
};
|
|
676
|
-
await walk(
|
|
807
|
+
await walk(join3(app, "Contents"));
|
|
677
808
|
await sign(app, opts.entitlements);
|
|
678
809
|
const verified = await runTool("codesign", ["--verify", "--deep", "--strict", app]);
|
|
679
810
|
if (!verified.success)
|
|
@@ -741,8 +872,8 @@ function notarytoolArguments(opts) {
|
|
|
741
872
|
}
|
|
742
873
|
function copyMacOSAppBundle(source, destination) {
|
|
743
874
|
try {
|
|
744
|
-
const info =
|
|
745
|
-
if (!existsSync4(info) || !existsSync4(
|
|
875
|
+
const info = join3(source, "Contents", "Info.plist");
|
|
876
|
+
if (!existsSync4(info) || !existsSync4(join3(source, "Contents", "MacOS")))
|
|
746
877
|
throw new Error(`Invalid prebuilt macOS application: ${source}`);
|
|
747
878
|
if (resolve(source) !== resolve(destination)) {
|
|
748
879
|
rmSync2(destination, { recursive: true, force: true });
|
|
@@ -754,29 +885,29 @@ function copyMacOSAppBundle(source, destination) {
|
|
|
754
885
|
}
|
|
755
886
|
}
|
|
756
887
|
function macOSRuntimeExecutablePath(appBundlePath) {
|
|
757
|
-
return
|
|
888
|
+
return join3(appBundlePath, "Contents", "Helpers", "CraftRuntime.app", "Contents", "MacOS", "craft");
|
|
758
889
|
}
|
|
759
890
|
function createMacOSAppBundle(opts) {
|
|
760
891
|
try {
|
|
761
892
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
762
|
-
const contents =
|
|
763
|
-
const macOS =
|
|
893
|
+
const contents = join3(outputPath, "Contents");
|
|
894
|
+
const macOS = join3(contents, "MacOS");
|
|
764
895
|
mkdirSync(macOS, { recursive: true });
|
|
765
|
-
mkdirSync(
|
|
766
|
-
copyFileSync(opts.nativeHost ? opts.nativeRuntimePath : binaryPath,
|
|
767
|
-
chmodSync(
|
|
896
|
+
mkdirSync(join3(contents, "Resources"), { recursive: true });
|
|
897
|
+
copyFileSync(opts.nativeHost ? opts.nativeRuntimePath : binaryPath, join3(macOS, name));
|
|
898
|
+
chmodSync(join3(macOS, name), 493);
|
|
768
899
|
for (const executable of additionalExecutables || []) {
|
|
769
900
|
if (!existsSync4(executable))
|
|
770
901
|
return { success: false, error: `Additional executable not found: ${executable}` };
|
|
771
|
-
const destination =
|
|
902
|
+
const destination = join3(macOS, basename(executable));
|
|
772
903
|
copyFileSync(executable, destination);
|
|
773
904
|
chmodSync(destination, 493);
|
|
774
905
|
}
|
|
775
906
|
if (opts.nativeHost) {
|
|
776
|
-
const backend =
|
|
907
|
+
const backend = join3(macOS, "craft-backend");
|
|
777
908
|
copyFileSync(binaryPath, backend);
|
|
778
909
|
chmodSync(backend, 493);
|
|
779
|
-
|
|
910
|
+
writeFileSync4(join3(contents, "Resources", "craft.json"), `${JSON.stringify({
|
|
780
911
|
title: name,
|
|
781
912
|
appName: name,
|
|
782
913
|
...opts.nativeWindow,
|
|
@@ -786,14 +917,14 @@ function createMacOSAppBundle(opts) {
|
|
|
786
917
|
} else if (opts.nativeRuntimePath) {
|
|
787
918
|
const helper = macOSRuntimeExecutablePath(outputPath);
|
|
788
919
|
const helperContents = resolve(helper, "..", "..");
|
|
789
|
-
mkdirSync(
|
|
920
|
+
mkdirSync(join3(helperContents, "MacOS"), { recursive: true });
|
|
790
921
|
copyFileSync(opts.nativeRuntimePath, helper);
|
|
791
922
|
chmodSync(helper, 493);
|
|
792
923
|
if (iconPath) {
|
|
793
|
-
mkdirSync(
|
|
794
|
-
copyFileSync(iconPath,
|
|
924
|
+
mkdirSync(join3(helperContents, "Resources"), { recursive: true });
|
|
925
|
+
copyFileSync(iconPath, join3(helperContents, "Resources", "icon.icns"));
|
|
795
926
|
}
|
|
796
|
-
|
|
927
|
+
writeFileSync4(join3(helperContents, "Info.plist"), macOSInfoPlist({
|
|
797
928
|
name,
|
|
798
929
|
executableName: "craft",
|
|
799
930
|
version: opts.version,
|
|
@@ -809,14 +940,14 @@ function createMacOSAppBundle(opts) {
|
|
|
809
940
|
if (!existsSync4(iconPath))
|
|
810
941
|
return { success: false, error: `Icon not found: ${iconPath}` };
|
|
811
942
|
iconName = basename(iconPath).replace(/\.icns$/i, "");
|
|
812
|
-
copyFileSync(iconPath,
|
|
943
|
+
copyFileSync(iconPath, join3(contents, "Resources", `${iconName}.icns`));
|
|
813
944
|
}
|
|
814
945
|
if (provisioningProfile) {
|
|
815
946
|
if (!existsSync4(provisioningProfile))
|
|
816
947
|
return { success: false, error: `Provisioning profile not found: ${provisioningProfile}` };
|
|
817
|
-
copyFileSync(provisioningProfile,
|
|
948
|
+
copyFileSync(provisioningProfile, join3(contents, "embedded.provisionprofile"));
|
|
818
949
|
}
|
|
819
|
-
|
|
950
|
+
writeFileSync4(join3(contents, "Info.plist"), macOSInfoPlist({ ...opts, iconName }));
|
|
820
951
|
return { success: true };
|
|
821
952
|
} catch (error) {
|
|
822
953
|
return { success: false, error: error.message };
|
|
@@ -826,7 +957,7 @@ function pathContentBytes(path) {
|
|
|
826
957
|
const stat = lstatSync(path);
|
|
827
958
|
if (!stat.isDirectory())
|
|
828
959
|
return stat.size;
|
|
829
|
-
return readdirSync2(path).reduce((total, entry) => total + pathContentBytes(
|
|
960
|
+
return readdirSync2(path).reduce((total, entry) => total + pathContentBytes(join3(path, entry)), 0);
|
|
830
961
|
}
|
|
831
962
|
function dmgCapacityMegabytes(contentBytes) {
|
|
832
963
|
if (!Number.isSafeInteger(contentBytes) || contentBytes < 0)
|
|
@@ -841,6 +972,8 @@ function dmgCreateArguments(opts, contentBytes) {
|
|
|
841
972
|
opts.volumeName,
|
|
842
973
|
"-srcfolder",
|
|
843
974
|
opts.appBundlePath,
|
|
975
|
+
"-fs",
|
|
976
|
+
"HFS+",
|
|
844
977
|
"-size",
|
|
845
978
|
`${dmgCapacityMegabytes(contentBytes)}m`,
|
|
846
979
|
"-ov",
|
|
@@ -874,24 +1007,70 @@ function runTool(tool, args) {
|
|
|
874
1007
|
proc.on("error", (err) => resolve({ success: false, error: err.message }));
|
|
875
1008
|
});
|
|
876
1009
|
}
|
|
877
|
-
async function
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
for (let attempt = 1
|
|
883
|
-
const
|
|
1010
|
+
async function detachDiskImage(mount, options = {}) {
|
|
1011
|
+
const run = options.run ?? runHdiutil;
|
|
1012
|
+
const wait = options.wait ?? ((ms) => new Promise((resolve) => {
|
|
1013
|
+
setTimeout(resolve, ms);
|
|
1014
|
+
}));
|
|
1015
|
+
for (let attempt = 1;; attempt++) {
|
|
1016
|
+
const forced = attempt >= HDIUTIL_MAX_ATTEMPTS;
|
|
1017
|
+
const result = await run(forced ? ["detach", mount, "-force"] : ["detach", mount]);
|
|
884
1018
|
if (result.success)
|
|
885
|
-
return { success: true
|
|
886
|
-
failures.push(`attempt ${attempt}: ${result.error}`);
|
|
1019
|
+
return { success: true };
|
|
887
1020
|
if (!shouldRetryHdiutil(result.error, attempt))
|
|
888
|
-
return { success: false, error:
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
1021
|
+
return { success: false, error: result.error };
|
|
1022
|
+
await wait(attempt * 2000);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
async function createDiskImage(opts) {
|
|
1026
|
+
if (!/^[^/:\n]{1,27}$/.test(opts.volumeName))
|
|
1027
|
+
return { success: false, error: `Invalid DMG volume name "${opts.volumeName}"; must be 1..27 chars without /, :, or newline` };
|
|
1028
|
+
const scratch = createTempDir("craft-installer-");
|
|
1029
|
+
const payload = join3(scratch, "payload");
|
|
1030
|
+
const mount = join3(scratch, "mount");
|
|
1031
|
+
const writable = join3(scratch, "installer.dmg");
|
|
1032
|
+
let mounted = false;
|
|
1033
|
+
const run = async (tool, args) => {
|
|
1034
|
+
const result = await runTool(tool, args);
|
|
1035
|
+
if (!result.success)
|
|
1036
|
+
throw new Error(result.error);
|
|
1037
|
+
return result;
|
|
1038
|
+
};
|
|
1039
|
+
try {
|
|
1040
|
+
mkdirSync(payload);
|
|
1041
|
+
mkdirSync(mount);
|
|
1042
|
+
const bundleName = basename(opts.appBundlePath);
|
|
1043
|
+
await run("ditto", [opts.appBundlePath, join3(payload, bundleName)]);
|
|
1044
|
+
symlinkSync("/Applications", join3(payload, "Applications"));
|
|
1045
|
+
mkdirSync(join3(payload, ".background"));
|
|
1046
|
+
writeFileSync4(join3(payload, ".background", "installer.png"), installerBackground);
|
|
1047
|
+
const args = dmgCreateArguments({ ...opts, appBundlePath: payload, outputPath: writable }, pathContentBytes(payload));
|
|
1048
|
+
args[args.indexOf("ULMO")] = "UDRW";
|
|
1049
|
+
for (let attempt = 1;; attempt++) {
|
|
1050
|
+
const result = await runHdiutil(args);
|
|
1051
|
+
if (result.success)
|
|
1052
|
+
break;
|
|
1053
|
+
if (!shouldRetryHdiutil(result.error, attempt))
|
|
1054
|
+
throw new Error(result.error);
|
|
1055
|
+
rmSync2(writable, { force: true });
|
|
1056
|
+
await new Promise((resolve) => setTimeout(resolve, attempt * 2000));
|
|
1057
|
+
}
|
|
1058
|
+
await run("hdiutil", ["attach", writable, "-nobrowse", "-mountpoint", mount]);
|
|
1059
|
+
mounted = true;
|
|
1060
|
+
writeInstallerLayout(mount, opts.volumeName, bundleName);
|
|
1061
|
+
const detached = await detachDiskImage(mount);
|
|
1062
|
+
if (!detached.success)
|
|
1063
|
+
throw new Error(detached.error);
|
|
1064
|
+
mounted = false;
|
|
1065
|
+
await run("hdiutil", ["convert", writable, "-format", "ULMO", "-ov", "-o", opts.outputPath]);
|
|
1066
|
+
return { success: true, outputPath: opts.outputPath };
|
|
1067
|
+
} catch (error) {
|
|
1068
|
+
return { success: false, error: error instanceof Error ? error.message : String(error) };
|
|
1069
|
+
} finally {
|
|
1070
|
+
if (mounted)
|
|
1071
|
+
await runTool("hdiutil", ["detach", mount, "-force"]);
|
|
1072
|
+
removeTempDir(scratch);
|
|
892
1073
|
}
|
|
893
|
-
return { success: false, error: failures.join(`
|
|
894
|
-
`) };
|
|
895
1074
|
}
|
|
896
1075
|
function pkgbuildComponentPlist(rootRelativeBundlePath) {
|
|
897
1076
|
return `<?xml version="1.0" encoding="UTF-8"?>
|
|
@@ -948,14 +1127,14 @@ async function createPKG(opts) {
|
|
|
948
1127
|
}
|
|
949
1128
|
const tempDir = createTempDir("craft-pkg-");
|
|
950
1129
|
try {
|
|
951
|
-
const root =
|
|
952
|
-
const appsDir =
|
|
1130
|
+
const root = join3(tempDir, "root");
|
|
1131
|
+
const appsDir = join3(root, "Applications");
|
|
953
1132
|
mkdirSync(appsDir, { recursive: true, mode: 493 });
|
|
954
1133
|
chmodSync(root, 493);
|
|
955
1134
|
const bundleName = basename(opts.appBundlePath);
|
|
956
|
-
cpSync(opts.appBundlePath,
|
|
957
|
-
const componentPlistPath =
|
|
958
|
-
|
|
1135
|
+
cpSync(opts.appBundlePath, join3(appsDir, bundleName), { recursive: true });
|
|
1136
|
+
const componentPlistPath = join3(tempDir, "component.plist");
|
|
1137
|
+
writeFileSync4(componentPlistPath, pkgbuildComponentPlist(`Applications/${bundleName}`));
|
|
959
1138
|
const built = await runTool("pkgbuild", pkgbuildArguments({
|
|
960
1139
|
root,
|
|
961
1140
|
componentPlistPath,
|
|
@@ -1089,14 +1268,14 @@ async function createMSI(opts) {
|
|
|
1089
1268
|
try {
|
|
1090
1269
|
const binaryName = windowsExecutableName(opts.name);
|
|
1091
1270
|
const additionalFiles = windowsCompanionFiles(opts.additionalFiles, binaryName);
|
|
1092
|
-
const sourcePath =
|
|
1093
|
-
const wxsPath =
|
|
1094
|
-
const wixobjPath =
|
|
1271
|
+
const sourcePath = join3(tempDir, binaryName);
|
|
1272
|
+
const wxsPath = join3(tempDir, "installer.wxs");
|
|
1273
|
+
const wixobjPath = join3(tempDir, "installer.wixobj");
|
|
1095
1274
|
copyFileSync(opts.binaryPath, sourcePath);
|
|
1096
|
-
|
|
1275
|
+
writeFileSync4(join3(tempDir, WINDOWS_NOTIFICATION_ID_FILE), windowsNotificationAppId(opts.name, opts.manufacturer));
|
|
1097
1276
|
for (const file of additionalFiles)
|
|
1098
|
-
copyFileSync(file.path,
|
|
1099
|
-
|
|
1277
|
+
copyFileSync(file.path, join3(tempDir, file.name));
|
|
1278
|
+
writeFileSync4(wxsPath, renderWixSource(opts, binaryName, additionalFiles.map((file) => file.name)));
|
|
1100
1279
|
await runCommand("candle.exe", candleArguments(opts.architecture, wixobjPath, wxsPath), tempDir);
|
|
1101
1280
|
await runCommand("light.exe", ["-nologo", "-sval", "-out", opts.outputPath, wixobjPath], tempDir);
|
|
1102
1281
|
if (opts.certificatePath) {
|
|
@@ -1125,7 +1304,7 @@ async function createZIP(opts) {
|
|
|
1125
1304
|
for (const file of additionalFiles)
|
|
1126
1305
|
entries.push({ name: file.name, data: new Uint8Array(readFileSync2(file.path)) });
|
|
1127
1306
|
const zip = buildZip(entries);
|
|
1128
|
-
|
|
1307
|
+
writeFileSync4(opts.outputPath, zip);
|
|
1129
1308
|
return { success: true, outputPath: opts.outputPath };
|
|
1130
1309
|
} catch (err) {
|
|
1131
1310
|
return { success: false, error: `Failed to write ZIP: ${err.message}` };
|
|
@@ -1158,15 +1337,15 @@ async function createDEB(opts) {
|
|
|
1158
1337
|
const desktopContent = linuxDesktopEntry(opts.name, sanitizedName, opts.urlSchemes, opts.launchUrl);
|
|
1159
1338
|
const tempDir = createTempDir("craft-deb-");
|
|
1160
1339
|
staging = tempDir;
|
|
1161
|
-
const debianDir =
|
|
1162
|
-
const binDir =
|
|
1163
|
-
const applicationsDir =
|
|
1340
|
+
const debianDir = join3(tempDir, "DEBIAN");
|
|
1341
|
+
const binDir = join3(tempDir, "usr", "bin");
|
|
1342
|
+
const applicationsDir = join3(tempDir, "usr", "share", "applications");
|
|
1164
1343
|
mkdirSync(debianDir, { recursive: true });
|
|
1165
1344
|
mkdirSync(binDir, { recursive: true });
|
|
1166
1345
|
mkdirSync(applicationsDir, { recursive: true });
|
|
1167
1346
|
const binaryName = sanitizedName;
|
|
1168
|
-
copyFileSync(opts.binaryPath,
|
|
1169
|
-
chmodSync(
|
|
1347
|
+
copyFileSync(opts.binaryPath, join3(binDir, binaryName));
|
|
1348
|
+
chmodSync(join3(binDir, binaryName), 493);
|
|
1170
1349
|
const controlContent = `Package: ${sanitizedName}
|
|
1171
1350
|
Version: ${opts.version}
|
|
1172
1351
|
Section: utils
|
|
@@ -1176,8 +1355,8 @@ Depends: ${opts.dependencies.join(", ")}
|
|
|
1176
1355
|
Maintainer: ${maintainer}
|
|
1177
1356
|
Description: ${description || opts.name}
|
|
1178
1357
|
`;
|
|
1179
|
-
|
|
1180
|
-
|
|
1358
|
+
writeFileSync4(join3(debianDir, "control"), controlContent);
|
|
1359
|
+
writeFileSync4(join3(applicationsDir, `${binaryName}.desktop`), desktopContent);
|
|
1181
1360
|
const proc = spawn("dpkg-deb", ["--build", tempDir, opts.outputPath]);
|
|
1182
1361
|
proc.on("close", (code) => {
|
|
1183
1362
|
removeTempDir(tempDir);
|
|
@@ -1201,11 +1380,11 @@ Description: ${description || opts.name}
|
|
|
1201
1380
|
async function createRPM(opts) {
|
|
1202
1381
|
return new Promise((resolve) => {
|
|
1203
1382
|
try {
|
|
1204
|
-
const buildRoot =
|
|
1205
|
-
const specDir =
|
|
1206
|
-
const sourcesDir =
|
|
1207
|
-
const buildDir =
|
|
1208
|
-
const rpmsDir =
|
|
1383
|
+
const buildRoot = join3(homedir(), "rpmbuild");
|
|
1384
|
+
const specDir = join3(buildRoot, "SPECS");
|
|
1385
|
+
const sourcesDir = join3(buildRoot, "SOURCES");
|
|
1386
|
+
const buildDir = join3(buildRoot, "BUILD");
|
|
1387
|
+
const rpmsDir = join3(buildRoot, "RPMS");
|
|
1209
1388
|
mkdirSync(specDir, { recursive: true });
|
|
1210
1389
|
mkdirSync(sourcesDir, { recursive: true });
|
|
1211
1390
|
mkdirSync(buildDir, { recursive: true });
|
|
@@ -1229,7 +1408,7 @@ async function createRPM(opts) {
|
|
|
1229
1408
|
}
|
|
1230
1409
|
return r;
|
|
1231
1410
|
}).join(", ");
|
|
1232
|
-
copyFileSync(opts.binaryPath,
|
|
1411
|
+
copyFileSync(opts.binaryPath, join3(sourcesDir, sanitizedName));
|
|
1233
1412
|
const specContent = `Name: ${sanitizedName}
|
|
1234
1413
|
Version: ${opts.version}
|
|
1235
1414
|
Release: 1%{?dist}
|
|
@@ -1247,13 +1426,13 @@ install -m 755 %{SOURCE0} %{buildroot}/usr/bin/${sanitizedName}
|
|
|
1247
1426
|
%files
|
|
1248
1427
|
/usr/bin/${sanitizedName}
|
|
1249
1428
|
`;
|
|
1250
|
-
const specPath =
|
|
1251
|
-
|
|
1429
|
+
const specPath = join3(specDir, `${opts.name.toLowerCase()}.spec`);
|
|
1430
|
+
writeFileSync4(specPath, specContent);
|
|
1252
1431
|
const proc = spawn("rpmbuild", ["-bb", specPath]);
|
|
1253
1432
|
proc.on("close", (code) => {
|
|
1254
1433
|
if (code === 0) {
|
|
1255
1434
|
const rpmName = `${opts.name.toLowerCase()}-${opts.version}-1.x86_64.rpm`;
|
|
1256
|
-
const builtRpmPath =
|
|
1435
|
+
const builtRpmPath = join3(rpmsDir, "x86_64", rpmName);
|
|
1257
1436
|
try {
|
|
1258
1437
|
copyFileSync(builtRpmPath, opts.outputPath);
|
|
1259
1438
|
resolve({ success: true, outputPath: opts.outputPath });
|
|
@@ -1278,22 +1457,22 @@ async function createAppImage(opts) {
|
|
|
1278
1457
|
try {
|
|
1279
1458
|
const appDir = createTempDir("craft-appimage-");
|
|
1280
1459
|
staging = appDir;
|
|
1281
|
-
const appDirPath =
|
|
1282
|
-
const binDir =
|
|
1283
|
-
const shareDir =
|
|
1460
|
+
const appDirPath = join3(appDir, `${opts.name}.AppDir`);
|
|
1461
|
+
const binDir = join3(appDirPath, "usr", "bin");
|
|
1462
|
+
const shareDir = join3(appDirPath, "usr", "share");
|
|
1284
1463
|
mkdirSync(binDir, { recursive: true });
|
|
1285
1464
|
mkdirSync(shareDir, { recursive: true });
|
|
1286
1465
|
const binaryName = opts.name.toLowerCase();
|
|
1287
|
-
copyFileSync(opts.binaryPath,
|
|
1288
|
-
chmodSync(
|
|
1466
|
+
copyFileSync(opts.binaryPath, join3(binDir, binaryName));
|
|
1467
|
+
chmodSync(join3(binDir, binaryName), 493);
|
|
1289
1468
|
const appRunContent = `#!/bin/bash
|
|
1290
1469
|
SELF=$(readlink -f "$0")
|
|
1291
1470
|
HERE=\${SELF%/*}
|
|
1292
1471
|
export PATH="\${HERE}/usr/bin/:\${PATH}"
|
|
1293
1472
|
exec "\${HERE}/usr/bin/${binaryName}" "$@"
|
|
1294
1473
|
`;
|
|
1295
|
-
|
|
1296
|
-
chmodSync(
|
|
1474
|
+
writeFileSync4(join3(appDirPath, "AppRun"), appRunContent);
|
|
1475
|
+
chmodSync(join3(appDirPath, "AppRun"), 493);
|
|
1297
1476
|
const desktopContent = `[Desktop Entry]
|
|
1298
1477
|
Type=Application
|
|
1299
1478
|
Name=${opts.name}
|
|
@@ -1302,9 +1481,9 @@ Terminal=false
|
|
|
1302
1481
|
Categories=Utility;
|
|
1303
1482
|
Icon=${binaryName}
|
|
1304
1483
|
`;
|
|
1305
|
-
|
|
1484
|
+
writeFileSync4(join3(appDirPath, `${binaryName}.desktop`), desktopContent);
|
|
1306
1485
|
if (opts.iconPath && existsSync4(opts.iconPath)) {
|
|
1307
|
-
copyFileSync(opts.iconPath,
|
|
1486
|
+
copyFileSync(opts.iconPath, join3(appDirPath, `${binaryName}.png`));
|
|
1308
1487
|
} else {
|
|
1309
1488
|
const placeholderPng = Buffer.from([
|
|
1310
1489
|
137,
|
|
@@ -1377,7 +1556,7 @@ Icon=${binaryName}
|
|
|
1377
1556
|
96,
|
|
1378
1557
|
130
|
|
1379
1558
|
]);
|
|
1380
|
-
|
|
1559
|
+
writeFileSync4(join3(appDirPath, `${binaryName}.png`), placeholderPng);
|
|
1381
1560
|
}
|
|
1382
1561
|
const proc = spawn("appimagetool", [appDirPath, opts.outputPath], {
|
|
1383
1562
|
env: { ...process.env, ARCH: "x86_64" }
|
|
@@ -1414,6 +1593,8 @@ function detectPlatform() {
|
|
|
1414
1593
|
}
|
|
1415
1594
|
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";
|
|
1416
1595
|
var init_package = __esm(() => {
|
|
1596
|
+
init_installer_layout();
|
|
1597
|
+
init_installer_background();
|
|
1417
1598
|
init_temp_dir();
|
|
1418
1599
|
DEFAULT_DEB_DEPENDENCIES = ["libgtk-3-0", "libwebkit2gtk-4.1-37", "libnotify-bin"];
|
|
1419
1600
|
CRC32_TABLE = (() => {
|
|
@@ -3047,7 +3228,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
3047
3228
|
`);
|
|
3048
3229
|
}
|
|
3049
3230
|
// package.json
|
|
3050
|
-
var version = "0.0.
|
|
3231
|
+
var version = "0.0.442";
|
|
3051
3232
|
|
|
3052
3233
|
// bin/cli.ts
|
|
3053
3234
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|