craft-native 0.0.276 → 0.0.290
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +16 -0
- package/dist/android/src/emulator.d.ts +4 -0
- package/dist/android/src/index.js +15 -6
- package/dist/android/templates/CraftNativeMutation.kt.template +35 -0
- package/dist/android/templates/CraftNativeShell.kt.template +12 -5
- package/dist/android/templates/CraftSnapshotFile.kt.template +26 -0
- package/dist/android/templates/MainActivityNative.kt.template +16 -0
- package/dist/api/index.d.ts +2 -2
- package/dist/api/mobile.d.ts +25 -0
- package/dist/browser/storage.d.ts +5 -3
- package/dist/browser.d.ts +1 -0
- package/dist/browser.js +31 -7
- package/dist/cli.js +131 -28
- package/dist/index.cjs +177 -27
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +181 -28
- package/dist/ios/src/index.js +7 -3
- package/dist/ios/templates/CraftApp.swift +44 -5
- package/dist/ios/templates/CraftHybrid.swift +21 -0
- package/dist/ios/templates/CraftNativeActions.swift +6 -0
- package/dist/ios/templates/CraftNativeFiles.swift +136 -0
- package/dist/ios/templates/CraftNativeMutation.swift +51 -0
- package/dist/ios/templates/CraftNativeScreen.swift +116 -8
- package/dist/ios/templates/CraftWatchApp.swift.template +303 -9
- package/dist/ios/templates/WatchExtension.Info.plist.template +1 -0
- package/dist/macos/templates/CraftNativeMutation.swift +51 -0
- package/dist/mobile.js +50 -0
- package/dist/package.d.ts +29 -3
- package/dist/types.d.ts +32 -0
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -130,18 +130,21 @@ import { spawn } from "child_process";
|
|
|
130
130
|
import { createHash } from "crypto";
|
|
131
131
|
import {
|
|
132
132
|
chmodSync,
|
|
133
|
+
closeSync,
|
|
133
134
|
copyFileSync,
|
|
134
135
|
cpSync,
|
|
135
136
|
existsSync as existsSync4,
|
|
136
137
|
lstatSync,
|
|
137
138
|
mkdirSync,
|
|
139
|
+
openSync,
|
|
138
140
|
readFileSync as readFileSync2,
|
|
141
|
+
readSync,
|
|
139
142
|
readdirSync as readdirSync2,
|
|
140
143
|
rmSync as rmSync2,
|
|
141
144
|
writeFileSync as writeFileSync3
|
|
142
145
|
} from "fs";
|
|
143
146
|
import { homedir } from "os";
|
|
144
|
-
import { basename, join as join2 } from "path";
|
|
147
|
+
import { basename, join as join2, resolve } from "path";
|
|
145
148
|
import { deflateRawSync } from "zlib";
|
|
146
149
|
function crc32(data) {
|
|
147
150
|
let c = 4294967295;
|
|
@@ -243,8 +246,10 @@ async function packageMacOS(config, outDir) {
|
|
|
243
246
|
const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
|
|
244
247
|
const opts = config.macos || {};
|
|
245
248
|
const hardenedRuntime = !opts.appStore;
|
|
249
|
+
if (opts.appStore && (!opts.entitlements || !opts.provisioningProfile))
|
|
250
|
+
return [{ success: false, platform: "macos", format: "app", error: "App Store packaging requires macos.entitlements and macos.provisioningProfile" }];
|
|
246
251
|
const appBundlePath = join2(outDir, `${name}.app`);
|
|
247
|
-
const appBundle = createMacOSAppBundle({
|
|
252
|
+
const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
|
|
248
253
|
name,
|
|
249
254
|
version,
|
|
250
255
|
bundleId,
|
|
@@ -268,25 +273,42 @@ async function packageMacOS(config, outDir) {
|
|
|
268
273
|
});
|
|
269
274
|
return results;
|
|
270
275
|
}
|
|
271
|
-
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
}
|
|
278
|
-
if (
|
|
279
|
-
|
|
280
|
-
|
|
276
|
+
try {
|
|
277
|
+
const contents = join2(appBundlePath, "Contents");
|
|
278
|
+
if (opts.provisioningProfile) {
|
|
279
|
+
const profile = join2(contents, "embedded.provisionprofile");
|
|
280
|
+
copyFileSync(opts.provisioningProfile, profile);
|
|
281
|
+
chmodSync(profile, 420);
|
|
282
|
+
}
|
|
283
|
+
if (opts.privacyManifest)
|
|
284
|
+
copyFileSync(opts.privacyManifest, join2(contents, "Resources", "PrivacyInfo.xcprivacy"));
|
|
285
|
+
if (opts.appBundlePath) {
|
|
286
|
+
const metadata = {
|
|
287
|
+
CFBundleVersion: opts.buildNumber,
|
|
288
|
+
LSApplicationCategoryType: opts.category,
|
|
289
|
+
LSMinimumSystemVersion: opts.minimumSystemVersion,
|
|
290
|
+
LSUIElement: opts.menuBarOnly
|
|
291
|
+
};
|
|
292
|
+
if (config.iconPath) {
|
|
293
|
+
const icon = basename(config.iconPath);
|
|
294
|
+
copyFileSync(config.iconPath, join2(contents, "Resources", icon));
|
|
295
|
+
metadata.CFBundleIconFile = icon;
|
|
296
|
+
}
|
|
297
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
298
|
+
if (value === undefined)
|
|
299
|
+
continue;
|
|
300
|
+
const result = await runTool("plutil", ["-replace", key, typeof value === "boolean" ? "-bool" : "-string", String(value), join2(contents, "Info.plist")]);
|
|
301
|
+
if (!result.success)
|
|
302
|
+
throw new Error(result.error);
|
|
303
|
+
}
|
|
281
304
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
}
|
|
289
|
-
return results;
|
|
305
|
+
if (opts.signIdentity) {
|
|
306
|
+
await signMacOSAppBundle(appBundlePath, bundleId, opts, hardenedRuntime);
|
|
307
|
+
} else if (opts.appStore) {
|
|
308
|
+
throw new Error('App Store packaging requires macos.signIdentity (a "3rd Party Mac Developer Application" identity)');
|
|
309
|
+
}
|
|
310
|
+
} catch (error) {
|
|
311
|
+
return [{ success: false, platform: "macos", format: "app", error: error.message }];
|
|
290
312
|
}
|
|
291
313
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
292
314
|
if (opts.dmg !== false) {
|
|
@@ -310,7 +332,8 @@ async function packageMacOS(config, outDir) {
|
|
|
310
332
|
identifier: bundleId,
|
|
311
333
|
version,
|
|
312
334
|
appStore: opts.appStore === true,
|
|
313
|
-
installerIdentity: opts.installerIdentity
|
|
335
|
+
installerIdentity: opts.installerIdentity,
|
|
336
|
+
signingKeychain: opts.signingKeychain
|
|
314
337
|
});
|
|
315
338
|
results.push({
|
|
316
339
|
success: pkgResult.success,
|
|
@@ -327,19 +350,21 @@ async function packageMacOS(config, outDir) {
|
|
|
327
350
|
async function notarizeIfRequested(opts, artifactPath, format) {
|
|
328
351
|
if (!opts.notarize)
|
|
329
352
|
return [];
|
|
330
|
-
if (!opts.appleId || !opts.applePassword || !opts.teamId) {
|
|
353
|
+
if (!opts.notaryKeychainProfile && !opts.notaryApiKey && (!opts.appleId || !opts.applePassword || !opts.teamId)) {
|
|
331
354
|
return [{
|
|
332
355
|
success: false,
|
|
333
356
|
platform: "macos",
|
|
334
357
|
format: `${format} (notarize)`,
|
|
335
|
-
error: "Notarization requires
|
|
358
|
+
error: "Notarization requires a keychain profile, API key, or Apple ID/password/team ID"
|
|
336
359
|
}];
|
|
337
360
|
}
|
|
338
361
|
const submitted = await runTool("xcrun", notarytoolArguments({
|
|
339
362
|
artifactPath,
|
|
340
363
|
appleId: opts.appleId,
|
|
341
364
|
applePassword: opts.applePassword,
|
|
342
|
-
teamId: opts.teamId
|
|
365
|
+
teamId: opts.teamId,
|
|
366
|
+
keychainProfile: opts.notaryKeychainProfile,
|
|
367
|
+
apiKey: opts.notaryApiKey
|
|
343
368
|
}));
|
|
344
369
|
if (!submitted.success)
|
|
345
370
|
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: submitted.error }];
|
|
@@ -548,6 +573,59 @@ ${body}
|
|
|
548
573
|
</dict>
|
|
549
574
|
</plist>`;
|
|
550
575
|
}
|
|
576
|
+
async function signMacOSAppBundle(app, bundleId, opts, hardenedRuntime) {
|
|
577
|
+
const scratch = createTempDir("craft-sign-");
|
|
578
|
+
try {
|
|
579
|
+
let helperEntitlements = opts.helperEntitlements;
|
|
580
|
+
if (opts.appStore && !helperEntitlements) {
|
|
581
|
+
helperEntitlements = join2(scratch, "inherit.plist");
|
|
582
|
+
writeFileSync3(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>');
|
|
583
|
+
}
|
|
584
|
+
const extracted = await runTool("plutil", ["-extract", "CFBundleExecutable", "raw", "-o", "-", join2(app, "Contents", "Info.plist")]);
|
|
585
|
+
if (!extracted.success)
|
|
586
|
+
throw new Error(extracted.error);
|
|
587
|
+
const main = join2(app, "Contents", "MacOS", extracted.stdout.trim());
|
|
588
|
+
const sign = async (path, entitlements, identifier) => {
|
|
589
|
+
const signed = await runTool("codesign", codesignArguments({ path, identity: opts.signIdentity, entitlements, hardenedRuntime, identifier, keychain: opts.signingKeychain, deep: false }));
|
|
590
|
+
if (!signed.success)
|
|
591
|
+
throw new Error(signed.error);
|
|
592
|
+
};
|
|
593
|
+
const walk = async (directory) => {
|
|
594
|
+
for (const entry of readdirSync2(directory)) {
|
|
595
|
+
const path = join2(directory, entry);
|
|
596
|
+
const stat = lstatSync(path);
|
|
597
|
+
if (stat.isSymbolicLink())
|
|
598
|
+
continue;
|
|
599
|
+
if (stat.isDirectory()) {
|
|
600
|
+
await walk(path);
|
|
601
|
+
if (/\.(?:app|framework|xpc|appex|bundle)$/.test(entry))
|
|
602
|
+
await sign(path, /\.(?:app|xpc|appex)$/.test(entry) ? helperEntitlements : undefined);
|
|
603
|
+
} else if (path !== main && stat.isFile() && isMachO(path)) {
|
|
604
|
+
const executable = (stat.mode & 73) !== 0 && !/\.(?:dylib|so)$/.test(entry);
|
|
605
|
+
await sign(path, executable ? helperEntitlements : undefined, `${bundleId}.${entry}`);
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
};
|
|
609
|
+
await walk(join2(app, "Contents"));
|
|
610
|
+
await sign(app, opts.entitlements);
|
|
611
|
+
const verified = await runTool("codesign", ["--verify", "--deep", "--strict", app]);
|
|
612
|
+
if (!verified.success)
|
|
613
|
+
throw new Error(verified.error);
|
|
614
|
+
} finally {
|
|
615
|
+
removeTempDir(scratch);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
function isMachO(path) {
|
|
619
|
+
const fd = openSync(path, "r");
|
|
620
|
+
try {
|
|
621
|
+
const magic = Buffer.alloc(4);
|
|
622
|
+
if (readSync(fd, magic, 0, 4, 0) !== 4)
|
|
623
|
+
return false;
|
|
624
|
+
return [4277009102, 3472551422, 4277009103, 3489328638, 3405691582, 3199925962, 3405691583, 3216703178].includes(magic.readUInt32BE());
|
|
625
|
+
} finally {
|
|
626
|
+
closeSync(fd);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
551
629
|
function codesignArguments(opts) {
|
|
552
630
|
return [
|
|
553
631
|
"--force",
|
|
@@ -556,7 +634,9 @@ function codesignArguments(opts) {
|
|
|
556
634
|
...opts.identity === "-" ? [] : ["--timestamp"],
|
|
557
635
|
...opts.hardenedRuntime ? ["--options", "runtime"] : [],
|
|
558
636
|
...opts.entitlements ? ["--entitlements", opts.entitlements] : [],
|
|
559
|
-
"--
|
|
637
|
+
...opts.identifier ? ["--identifier", opts.identifier] : [],
|
|
638
|
+
...opts.keychain ? ["--keychain", opts.keychain] : [],
|
|
639
|
+
...opts.deep === false ? [] : ["--deep"],
|
|
560
640
|
opts.path
|
|
561
641
|
];
|
|
562
642
|
}
|
|
@@ -567,10 +647,18 @@ function productbuildArguments(opts) {
|
|
|
567
647
|
"/Applications",
|
|
568
648
|
"--sign",
|
|
569
649
|
opts.identity,
|
|
650
|
+
...opts.keychain ? ["--keychain", opts.keychain] : [],
|
|
570
651
|
opts.outputPath
|
|
571
652
|
];
|
|
572
653
|
}
|
|
573
654
|
function notarytoolArguments(opts) {
|
|
655
|
+
const base = ["notarytool", "submit", opts.artifactPath, "--wait"];
|
|
656
|
+
if (opts.keychainProfile)
|
|
657
|
+
return [...base, "--keychain-profile", opts.keychainProfile];
|
|
658
|
+
if (opts.apiKey)
|
|
659
|
+
return [...base, "--key", opts.apiKey.path, "--key-id", opts.apiKey.keyId, "--issuer", opts.apiKey.issuer];
|
|
660
|
+
if (!opts.appleId || !opts.applePassword || !opts.teamId)
|
|
661
|
+
throw new Error("Notarization credentials are incomplete");
|
|
574
662
|
return [
|
|
575
663
|
"notarytool",
|
|
576
664
|
"submit",
|
|
@@ -584,6 +672,20 @@ function notarytoolArguments(opts) {
|
|
|
584
672
|
"--wait"
|
|
585
673
|
];
|
|
586
674
|
}
|
|
675
|
+
function copyMacOSAppBundle(source, destination) {
|
|
676
|
+
try {
|
|
677
|
+
const info = join2(source, "Contents", "Info.plist");
|
|
678
|
+
if (!existsSync4(info) || !existsSync4(join2(source, "Contents", "MacOS")))
|
|
679
|
+
throw new Error(`Invalid prebuilt macOS application: ${source}`);
|
|
680
|
+
if (resolve(source) !== resolve(destination)) {
|
|
681
|
+
rmSync2(destination, { recursive: true, force: true });
|
|
682
|
+
cpSync(source, destination, { recursive: true });
|
|
683
|
+
}
|
|
684
|
+
return { success: true };
|
|
685
|
+
} catch (error) {
|
|
686
|
+
return { success: false, error: error.message };
|
|
687
|
+
}
|
|
688
|
+
}
|
|
587
689
|
function createMacOSAppBundle(opts) {
|
|
588
690
|
try {
|
|
589
691
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
@@ -663,7 +765,7 @@ function runTool(tool, args) {
|
|
|
663
765
|
});
|
|
664
766
|
proc.on("close", (code) => {
|
|
665
767
|
if (code === 0)
|
|
666
|
-
resolve({ success: true });
|
|
768
|
+
resolve({ success: true, stdout });
|
|
667
769
|
else
|
|
668
770
|
resolve({ success: false, error: formatPackagingCommandError(tool, code, stdout, stderr) });
|
|
669
771
|
});
|
|
@@ -737,7 +839,8 @@ async function createPKG(opts) {
|
|
|
737
839
|
const built = await runTool("productbuild", productbuildArguments({
|
|
738
840
|
appBundlePath: opts.appBundlePath,
|
|
739
841
|
outputPath: opts.outputPath,
|
|
740
|
-
identity: opts.installerIdentity
|
|
842
|
+
identity: opts.installerIdentity,
|
|
843
|
+
keychain: opts.signingKeychain
|
|
741
844
|
}));
|
|
742
845
|
return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
|
|
743
846
|
}
|
|
@@ -2842,7 +2945,7 @@ function pinCraftNativeDependency(packagePath, craftVersion) {
|
|
|
2842
2945
|
`);
|
|
2843
2946
|
}
|
|
2844
2947
|
// package.json
|
|
2845
|
-
var version = "0.0.
|
|
2948
|
+
var version = "0.0.290";
|
|
2846
2949
|
|
|
2847
2950
|
// bin/cli.ts
|
|
2848
2951
|
var spawnedFrom = process6.env[CRAFT_CLI_SPAWN_MARKER];
|
package/dist/index.cjs
CHANGED
|
@@ -118,6 +118,7 @@ __export(exports_src, {
|
|
|
118
118
|
extractBundle: () => extractBundle,
|
|
119
119
|
extractBundleFromDmg: () => extractBundleFromDmg,
|
|
120
120
|
extractBundleFromZip: () => extractBundleFromZip,
|
|
121
|
+
files: () => files,
|
|
121
122
|
focus: () => focus,
|
|
122
123
|
focusFilters: () => focusFilters,
|
|
123
124
|
foregroundService: () => foregroundService,
|
|
@@ -373,7 +374,7 @@ function craftBinaryNotFoundMessage(triedPath) {
|
|
|
373
374
|
`);
|
|
374
375
|
}
|
|
375
376
|
// package.json
|
|
376
|
-
var version = "0.0.
|
|
377
|
+
var version = "0.0.290";
|
|
377
378
|
|
|
378
379
|
// src/sdk-version.ts
|
|
379
380
|
var SDK_VERSION = version;
|
|
@@ -610,8 +611,10 @@ async function packageMacOS(config, outDir) {
|
|
|
610
611
|
const { name, version, bundleId = `com.myapp.${name.toLowerCase()}` } = config;
|
|
611
612
|
const opts = config.macos || {};
|
|
612
613
|
const hardenedRuntime = !opts.appStore;
|
|
614
|
+
if (opts.appStore && (!opts.entitlements || !opts.provisioningProfile))
|
|
615
|
+
return [{ success: false, platform: "macos", format: "app", error: "App Store packaging requires macos.entitlements and macos.provisioningProfile" }];
|
|
613
616
|
const appBundlePath = import_path.join(outDir, `${name}.app`);
|
|
614
|
-
const appBundle = createMacOSAppBundle({
|
|
617
|
+
const appBundle = opts.appBundlePath ? copyMacOSAppBundle(opts.appBundlePath, appBundlePath) : createMacOSAppBundle({
|
|
615
618
|
name,
|
|
616
619
|
version,
|
|
617
620
|
bundleId,
|
|
@@ -635,25 +638,42 @@ async function packageMacOS(config, outDir) {
|
|
|
635
638
|
});
|
|
636
639
|
return results;
|
|
637
640
|
}
|
|
638
|
-
|
|
639
|
-
const
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
}
|
|
645
|
-
if (
|
|
646
|
-
|
|
647
|
-
|
|
641
|
+
try {
|
|
642
|
+
const contents = import_path.join(appBundlePath, "Contents");
|
|
643
|
+
if (opts.provisioningProfile) {
|
|
644
|
+
const profile = import_path.join(contents, "embedded.provisionprofile");
|
|
645
|
+
import_fs.copyFileSync(opts.provisioningProfile, profile);
|
|
646
|
+
import_fs.chmodSync(profile, 420);
|
|
647
|
+
}
|
|
648
|
+
if (opts.privacyManifest)
|
|
649
|
+
import_fs.copyFileSync(opts.privacyManifest, import_path.join(contents, "Resources", "PrivacyInfo.xcprivacy"));
|
|
650
|
+
if (opts.appBundlePath) {
|
|
651
|
+
const metadata = {
|
|
652
|
+
CFBundleVersion: opts.buildNumber,
|
|
653
|
+
LSApplicationCategoryType: opts.category,
|
|
654
|
+
LSMinimumSystemVersion: opts.minimumSystemVersion,
|
|
655
|
+
LSUIElement: opts.menuBarOnly
|
|
656
|
+
};
|
|
657
|
+
if (config.iconPath) {
|
|
658
|
+
const icon = import_path.basename(config.iconPath);
|
|
659
|
+
import_fs.copyFileSync(config.iconPath, import_path.join(contents, "Resources", icon));
|
|
660
|
+
metadata.CFBundleIconFile = icon;
|
|
661
|
+
}
|
|
662
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
663
|
+
if (value === undefined)
|
|
664
|
+
continue;
|
|
665
|
+
const result = await runTool("plutil", ["-replace", key, typeof value === "boolean" ? "-bool" : "-string", String(value), import_path.join(contents, "Info.plist")]);
|
|
666
|
+
if (!result.success)
|
|
667
|
+
throw new Error(result.error);
|
|
668
|
+
}
|
|
648
669
|
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
}
|
|
656
|
-
return results;
|
|
670
|
+
if (opts.signIdentity) {
|
|
671
|
+
await signMacOSAppBundle(appBundlePath, bundleId, opts, hardenedRuntime);
|
|
672
|
+
} else if (opts.appStore) {
|
|
673
|
+
throw new Error('App Store packaging requires macos.signIdentity (a "3rd Party Mac Developer Application" identity)');
|
|
674
|
+
}
|
|
675
|
+
} catch (error) {
|
|
676
|
+
return [{ success: false, platform: "macos", format: "app", error: error.message }];
|
|
657
677
|
}
|
|
658
678
|
results.push({ success: true, platform: "macos", format: "app", outputPath: appBundlePath });
|
|
659
679
|
if (opts.dmg !== false) {
|
|
@@ -677,7 +697,8 @@ async function packageMacOS(config, outDir) {
|
|
|
677
697
|
identifier: bundleId,
|
|
678
698
|
version,
|
|
679
699
|
appStore: opts.appStore === true,
|
|
680
|
-
installerIdentity: opts.installerIdentity
|
|
700
|
+
installerIdentity: opts.installerIdentity,
|
|
701
|
+
signingKeychain: opts.signingKeychain
|
|
681
702
|
});
|
|
682
703
|
results.push({
|
|
683
704
|
success: pkgResult.success,
|
|
@@ -694,19 +715,21 @@ async function packageMacOS(config, outDir) {
|
|
|
694
715
|
async function notarizeIfRequested(opts, artifactPath, format) {
|
|
695
716
|
if (!opts.notarize)
|
|
696
717
|
return [];
|
|
697
|
-
if (!opts.appleId || !opts.applePassword || !opts.teamId) {
|
|
718
|
+
if (!opts.notaryKeychainProfile && !opts.notaryApiKey && (!opts.appleId || !opts.applePassword || !opts.teamId)) {
|
|
698
719
|
return [{
|
|
699
720
|
success: false,
|
|
700
721
|
platform: "macos",
|
|
701
722
|
format: `${format} (notarize)`,
|
|
702
|
-
error: "Notarization requires
|
|
723
|
+
error: "Notarization requires a keychain profile, API key, or Apple ID/password/team ID"
|
|
703
724
|
}];
|
|
704
725
|
}
|
|
705
726
|
const submitted = await runTool("xcrun", notarytoolArguments({
|
|
706
727
|
artifactPath,
|
|
707
728
|
appleId: opts.appleId,
|
|
708
729
|
applePassword: opts.applePassword,
|
|
709
|
-
teamId: opts.teamId
|
|
730
|
+
teamId: opts.teamId,
|
|
731
|
+
keychainProfile: opts.notaryKeychainProfile,
|
|
732
|
+
apiKey: opts.notaryApiKey
|
|
710
733
|
}));
|
|
711
734
|
if (!submitted.success)
|
|
712
735
|
return [{ success: false, platform: "macos", format: `${format} (notarize)`, error: submitted.error }];
|
|
@@ -916,6 +939,59 @@ ${body}
|
|
|
916
939
|
</dict>
|
|
917
940
|
</plist>`;
|
|
918
941
|
}
|
|
942
|
+
async function signMacOSAppBundle(app, bundleId, opts, hardenedRuntime) {
|
|
943
|
+
const scratch = createTempDir("craft-sign-");
|
|
944
|
+
try {
|
|
945
|
+
let helperEntitlements = opts.helperEntitlements;
|
|
946
|
+
if (opts.appStore && !helperEntitlements) {
|
|
947
|
+
helperEntitlements = import_path.join(scratch, "inherit.plist");
|
|
948
|
+
import_fs.writeFileSync(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>');
|
|
949
|
+
}
|
|
950
|
+
const extracted = await runTool("plutil", ["-extract", "CFBundleExecutable", "raw", "-o", "-", import_path.join(app, "Contents", "Info.plist")]);
|
|
951
|
+
if (!extracted.success)
|
|
952
|
+
throw new Error(extracted.error);
|
|
953
|
+
const main = import_path.join(app, "Contents", "MacOS", extracted.stdout.trim());
|
|
954
|
+
const sign = async (path, entitlements, identifier) => {
|
|
955
|
+
const signed = await runTool("codesign", codesignArguments({ path, identity: opts.signIdentity, entitlements, hardenedRuntime, identifier, keychain: opts.signingKeychain, deep: false }));
|
|
956
|
+
if (!signed.success)
|
|
957
|
+
throw new Error(signed.error);
|
|
958
|
+
};
|
|
959
|
+
const walk = async (directory) => {
|
|
960
|
+
for (const entry of import_fs.readdirSync(directory)) {
|
|
961
|
+
const path = import_path.join(directory, entry);
|
|
962
|
+
const stat = import_fs.lstatSync(path);
|
|
963
|
+
if (stat.isSymbolicLink())
|
|
964
|
+
continue;
|
|
965
|
+
if (stat.isDirectory()) {
|
|
966
|
+
await walk(path);
|
|
967
|
+
if (/\.(?:app|framework|xpc|appex|bundle)$/.test(entry))
|
|
968
|
+
await sign(path, /\.(?:app|xpc|appex)$/.test(entry) ? helperEntitlements : undefined);
|
|
969
|
+
} else if (path !== main && stat.isFile() && isMachO(path)) {
|
|
970
|
+
const executable = (stat.mode & 73) !== 0 && !/\.(?:dylib|so)$/.test(entry);
|
|
971
|
+
await sign(path, executable ? helperEntitlements : undefined, `${bundleId}.${entry}`);
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
};
|
|
975
|
+
await walk(import_path.join(app, "Contents"));
|
|
976
|
+
await sign(app, opts.entitlements);
|
|
977
|
+
const verified = await runTool("codesign", ["--verify", "--deep", "--strict", app]);
|
|
978
|
+
if (!verified.success)
|
|
979
|
+
throw new Error(verified.error);
|
|
980
|
+
} finally {
|
|
981
|
+
removeTempDir(scratch);
|
|
982
|
+
}
|
|
983
|
+
}
|
|
984
|
+
function isMachO(path) {
|
|
985
|
+
const fd = import_fs.openSync(path, "r");
|
|
986
|
+
try {
|
|
987
|
+
const magic = Buffer.alloc(4);
|
|
988
|
+
if (import_fs.readSync(fd, magic, 0, 4, 0) !== 4)
|
|
989
|
+
return false;
|
|
990
|
+
return [4277009102, 3472551422, 4277009103, 3489328638, 3405691582, 3199925962, 3405691583, 3216703178].includes(magic.readUInt32BE());
|
|
991
|
+
} finally {
|
|
992
|
+
import_fs.closeSync(fd);
|
|
993
|
+
}
|
|
994
|
+
}
|
|
919
995
|
function codesignArguments(opts) {
|
|
920
996
|
return [
|
|
921
997
|
"--force",
|
|
@@ -924,7 +1000,9 @@ function codesignArguments(opts) {
|
|
|
924
1000
|
...opts.identity === "-" ? [] : ["--timestamp"],
|
|
925
1001
|
...opts.hardenedRuntime ? ["--options", "runtime"] : [],
|
|
926
1002
|
...opts.entitlements ? ["--entitlements", opts.entitlements] : [],
|
|
927
|
-
"--
|
|
1003
|
+
...opts.identifier ? ["--identifier", opts.identifier] : [],
|
|
1004
|
+
...opts.keychain ? ["--keychain", opts.keychain] : [],
|
|
1005
|
+
...opts.deep === false ? [] : ["--deep"],
|
|
928
1006
|
opts.path
|
|
929
1007
|
];
|
|
930
1008
|
}
|
|
@@ -935,10 +1013,18 @@ function productbuildArguments(opts) {
|
|
|
935
1013
|
"/Applications",
|
|
936
1014
|
"--sign",
|
|
937
1015
|
opts.identity,
|
|
1016
|
+
...opts.keychain ? ["--keychain", opts.keychain] : [],
|
|
938
1017
|
opts.outputPath
|
|
939
1018
|
];
|
|
940
1019
|
}
|
|
941
1020
|
function notarytoolArguments(opts) {
|
|
1021
|
+
const base = ["notarytool", "submit", opts.artifactPath, "--wait"];
|
|
1022
|
+
if (opts.keychainProfile)
|
|
1023
|
+
return [...base, "--keychain-profile", opts.keychainProfile];
|
|
1024
|
+
if (opts.apiKey)
|
|
1025
|
+
return [...base, "--key", opts.apiKey.path, "--key-id", opts.apiKey.keyId, "--issuer", opts.apiKey.issuer];
|
|
1026
|
+
if (!opts.appleId || !opts.applePassword || !opts.teamId)
|
|
1027
|
+
throw new Error("Notarization credentials are incomplete");
|
|
942
1028
|
return [
|
|
943
1029
|
"notarytool",
|
|
944
1030
|
"submit",
|
|
@@ -952,6 +1038,20 @@ function notarytoolArguments(opts) {
|
|
|
952
1038
|
"--wait"
|
|
953
1039
|
];
|
|
954
1040
|
}
|
|
1041
|
+
function copyMacOSAppBundle(source, destination) {
|
|
1042
|
+
try {
|
|
1043
|
+
const info = import_path.join(source, "Contents", "Info.plist");
|
|
1044
|
+
if (!import_fs.existsSync(info) || !import_fs.existsSync(import_path.join(source, "Contents", "MacOS")))
|
|
1045
|
+
throw new Error(`Invalid prebuilt macOS application: ${source}`);
|
|
1046
|
+
if (import_path.resolve(source) !== import_path.resolve(destination)) {
|
|
1047
|
+
import_fs.rmSync(destination, { recursive: true, force: true });
|
|
1048
|
+
import_fs.cpSync(source, destination, { recursive: true });
|
|
1049
|
+
}
|
|
1050
|
+
return { success: true };
|
|
1051
|
+
} catch (error) {
|
|
1052
|
+
return { success: false, error: error.message };
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
955
1055
|
function createMacOSAppBundle(opts) {
|
|
956
1056
|
try {
|
|
957
1057
|
const { name, binaryPath, iconPath, provisioningProfile, additionalExecutables, outputPath } = opts;
|
|
@@ -1033,7 +1133,7 @@ function runTool(tool, args) {
|
|
|
1033
1133
|
});
|
|
1034
1134
|
proc.on("close", (code) => {
|
|
1035
1135
|
if (code === 0)
|
|
1036
|
-
resolve({ success: true });
|
|
1136
|
+
resolve({ success: true, stdout });
|
|
1037
1137
|
else
|
|
1038
1138
|
resolve({ success: false, error: formatPackagingCommandError(tool, code, stdout, stderr) });
|
|
1039
1139
|
});
|
|
@@ -1108,7 +1208,8 @@ async function createPKG(opts) {
|
|
|
1108
1208
|
const built = await runTool("productbuild", productbuildArguments({
|
|
1109
1209
|
appBundlePath: opts.appBundlePath,
|
|
1110
1210
|
outputPath: opts.outputPath,
|
|
1111
|
-
identity: opts.installerIdentity
|
|
1211
|
+
identity: opts.installerIdentity,
|
|
1212
|
+
keychain: opts.signingKeychain
|
|
1112
1213
|
}));
|
|
1113
1214
|
return built.success ? { success: true, outputPath: opts.outputPath } : { success: false, error: built.error };
|
|
1114
1215
|
}
|
|
@@ -5106,6 +5207,55 @@ var permissions = {
|
|
|
5106
5207
|
}
|
|
5107
5208
|
}
|
|
5108
5209
|
};
|
|
5210
|
+
var files = {
|
|
5211
|
+
async pickFile(options = {}) {
|
|
5212
|
+
const craft = getCraftMobile();
|
|
5213
|
+
if (typeof window !== "undefined" && craft?.files) {
|
|
5214
|
+
return craft.files.pickFile(options);
|
|
5215
|
+
}
|
|
5216
|
+
if (typeof document === "undefined") {
|
|
5217
|
+
throw new Error("File picker not available. Must run in Craft or a browser.");
|
|
5218
|
+
}
|
|
5219
|
+
return new Promise((resolve, reject) => {
|
|
5220
|
+
const input = document.createElement("input");
|
|
5221
|
+
input.type = "file";
|
|
5222
|
+
if (options.contentTypes?.length)
|
|
5223
|
+
input.accept = options.contentTypes.join(",");
|
|
5224
|
+
const requested = Number(options.maxSelections);
|
|
5225
|
+
const maxSelections = Number.isFinite(requested) && requested > 0 ? Math.min(20, Math.floor(requested)) : 1;
|
|
5226
|
+
input.multiple = maxSelections > 1;
|
|
5227
|
+
input.style.display = "none";
|
|
5228
|
+
let settled = false;
|
|
5229
|
+
const finish = (result) => {
|
|
5230
|
+
if (settled)
|
|
5231
|
+
return;
|
|
5232
|
+
settled = true;
|
|
5233
|
+
input.remove();
|
|
5234
|
+
result();
|
|
5235
|
+
};
|
|
5236
|
+
input.addEventListener("cancel", () => finish(() => resolve([])), { once: true });
|
|
5237
|
+
input.onchange = () => {
|
|
5238
|
+
const chosen = Array.from(input.files ?? []).slice(0, maxSelections);
|
|
5239
|
+
const limit = Number(options.maxBytes);
|
|
5240
|
+
if (Number.isFinite(limit) && limit > 0) {
|
|
5241
|
+
const oversized = chosen.find((file) => file.size > limit);
|
|
5242
|
+
if (oversized) {
|
|
5243
|
+
finish(() => reject(Object.assign(new Error("The selected file is too large"), { code: "FILE_TOO_LARGE" })));
|
|
5244
|
+
return;
|
|
5245
|
+
}
|
|
5246
|
+
}
|
|
5247
|
+
finish(() => resolve(chosen.map((file) => ({
|
|
5248
|
+
path: URL.createObjectURL(file),
|
|
5249
|
+
name: file.name,
|
|
5250
|
+
type: file.type || "application/octet-stream",
|
|
5251
|
+
size: file.size
|
|
5252
|
+
}))));
|
|
5253
|
+
};
|
|
5254
|
+
document.body.append(input);
|
|
5255
|
+
input.click();
|
|
5256
|
+
});
|
|
5257
|
+
}
|
|
5258
|
+
};
|
|
5109
5259
|
var camera = {
|
|
5110
5260
|
async takePicture(options = {}) {
|
|
5111
5261
|
const craft = getCraftMobile();
|
package/dist/index.d.cts
CHANGED
|
@@ -85,4 +85,4 @@ export declare function show(html: string, options?: WindowOptions): Promise<voi
|
|
|
85
85
|
* Quick helper to load a URL
|
|
86
86
|
*/
|
|
87
87
|
export declare function loadURL(url: string, options?: WindowOptions): Promise<void>;
|
|
88
|
-
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
|
88
|
+
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
package/dist/index.d.ts
CHANGED
|
@@ -85,4 +85,4 @@ export declare function show(html: string, options?: WindowOptions): Promise<voi
|
|
|
85
85
|
* Quick helper to load a URL
|
|
86
86
|
*/
|
|
87
87
|
export declare function loadURL(url: string, options?: WindowOptions): Promise<void>;
|
|
88
|
-
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|
|
88
|
+
export type { WindowOptions, CraftSidebarAPI, CraftNativeUIAPI, CraftContextMenuItem, CraftContextMenuResult, AppConfig, CraftTrayAPI, CraftWindowAPI, CraftAppAPI, CraftBridgeAPI, CraftTimersAPI, Permission, HapticType, CraftHapticsAPI, CameraOptions, PhotoPickerOptions, CraftMobileAPI, CraftFileSystemAPI, CraftFsWatchEvent, CraftFsWatchHandle, CraftDatabaseAPI, CraftHttpAPI, CraftCryptoAPI, CraftCapabilities, CapabilityNamespace, CapabilityNamespaceStatus, CapabilityAction, CraftPreferencesAPI, CraftPreferencesInfo, CraftSettingsAPI, PreferenceValue, CraftEventType, CraftEventMap, CraftEventHandler, CraftEventEmitter, IOSConfig, AndroidConfig, MacOSConfig, WindowsConfig, LinuxConfig, CraftAppConfig, } from './types.js';
|