electrobun 1.16.0 → 1.17.0-beta.0
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 +36 -2
- package/dist/api/bun/ElectrobunConfig.ts +16 -0
- package/dist/api/bun/core/BrowserView.ts +41 -13
- package/dist/api/bun/core/Socket.ts +8 -0
- package/dist/api/bun/core/Updater.ts +2 -4
- package/dist/api/bun/core/Utils.ts +18 -15
- package/dist/api/bun/index.ts +137 -0
- package/dist/api/bun/preload/build.ts +6 -4
- package/dist/api/bun/proc/native.ts +271 -238
- package/dist/api/shared/bun-version.ts +1 -1
- package/package.json +3 -2
- package/src/cli/index.ts +281 -21
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electrobun",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.17.0-beta.0",
|
|
4
4
|
"description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blackboard Technologies Inc.",
|
|
@@ -14,7 +14,8 @@
|
|
|
14
14
|
"exports": {
|
|
15
15
|
".": "./dist/api/bun/index.ts",
|
|
16
16
|
"./bun": "./dist/api/bun/index.ts",
|
|
17
|
-
"./view": "./dist/api/browser/index.ts"
|
|
17
|
+
"./view": "./dist/api/browser/index.ts",
|
|
18
|
+
"./carrot": "./dist/api/carrot/bun.ts"
|
|
18
19
|
},
|
|
19
20
|
"type": "module",
|
|
20
21
|
"bin": {
|
package/src/cli/index.ts
CHANGED
|
@@ -482,35 +482,41 @@ async function ensureBunBinary(
|
|
|
482
482
|
targetOS: "macos" | "win" | "linux",
|
|
483
483
|
targetArch: "arm64" | "x64",
|
|
484
484
|
bunVersion?: string,
|
|
485
|
+
bunnyBun?: string,
|
|
485
486
|
): Promise<string> {
|
|
486
|
-
|
|
487
|
+
const effectiveVersion = bunnyBun || bunVersion;
|
|
488
|
+
if (!effectiveVersion) {
|
|
487
489
|
return getPlatformPaths(targetOS, targetArch).BUN_BINARY;
|
|
488
490
|
}
|
|
489
491
|
|
|
490
492
|
const binExt = targetOS === "win" ? ".exe" : "";
|
|
491
|
-
const
|
|
493
|
+
const cacheSubdir = bunnyBun ? "bunny-bun-override" : "bun-override";
|
|
494
|
+
const overrideDir = join(ELECTROBUN_CACHE_PATH, cacheSubdir, `${targetOS}-${targetArch}`);
|
|
492
495
|
const overrideBinary = join(overrideDir, `bun${binExt}`);
|
|
493
496
|
const versionFile = join(overrideDir, ".bun-version");
|
|
494
497
|
|
|
495
498
|
// Check if already downloaded with matching version
|
|
496
499
|
if (existsSync(overrideBinary) && existsSync(versionFile)) {
|
|
497
500
|
const cachedVersion = readFileSync(versionFile, "utf8").trim();
|
|
498
|
-
if (cachedVersion ===
|
|
501
|
+
if (cachedVersion === effectiveVersion) {
|
|
499
502
|
console.log(
|
|
500
|
-
|
|
503
|
+
`${bunnyBun ? "Bunny" : "Custom"} Bun ${effectiveVersion} already cached for ${targetOS}-${targetArch}`,
|
|
501
504
|
);
|
|
502
505
|
return overrideBinary;
|
|
503
506
|
}
|
|
504
|
-
// Version mismatch - remove stale cache
|
|
505
507
|
console.log(
|
|
506
|
-
`Cached Bun version "${cachedVersion}" does not match requested "${
|
|
508
|
+
`Cached Bun version "${cachedVersion}" does not match requested "${effectiveVersion}", re-downloading...`,
|
|
507
509
|
);
|
|
508
510
|
rmSync(overrideDir, { recursive: true, force: true });
|
|
509
511
|
} else if (existsSync(overrideDir)) {
|
|
510
512
|
rmSync(overrideDir, { recursive: true, force: true });
|
|
511
513
|
}
|
|
512
514
|
|
|
513
|
-
|
|
515
|
+
if (bunnyBun) {
|
|
516
|
+
await downloadBunnyBun(bunnyBun, targetOS, targetArch);
|
|
517
|
+
} else {
|
|
518
|
+
await downloadCustomBun(effectiveVersion, targetOS, targetArch);
|
|
519
|
+
}
|
|
514
520
|
return overrideBinary;
|
|
515
521
|
}
|
|
516
522
|
|
|
@@ -664,6 +670,123 @@ async function downloadCustomBun(
|
|
|
664
670
|
}
|
|
665
671
|
}
|
|
666
672
|
|
|
673
|
+
/**
|
|
674
|
+
* Downloads Electrobunny's Bun fork from blackboardsh/bun GitHub releases.
|
|
675
|
+
* Release assets follow the same naming convention as oven-sh/bun:
|
|
676
|
+
* bun-darwin-aarch64.zip, bun-linux-x64.zip, etc.
|
|
677
|
+
*/
|
|
678
|
+
async function downloadBunnyBun(
|
|
679
|
+
releaseTag: string,
|
|
680
|
+
platformOS: "macos" | "win" | "linux",
|
|
681
|
+
platformArch: "arm64" | "x64",
|
|
682
|
+
) {
|
|
683
|
+
let assetName: string;
|
|
684
|
+
let dirName: string;
|
|
685
|
+
|
|
686
|
+
// Asset names match the CI artifact names from blackboardsh/bun
|
|
687
|
+
if (platformOS === "win") {
|
|
688
|
+
assetName = "bun-windows-x64.zip";
|
|
689
|
+
dirName = "bun-windows-x64";
|
|
690
|
+
} else if (platformOS === "macos") {
|
|
691
|
+
assetName = platformArch === "arm64" ? "bun-darwin-arm64.zip" : "bun-darwin-x64.zip";
|
|
692
|
+
dirName = platformArch === "arm64" ? "bun-darwin-arm64" : "bun-darwin-x64";
|
|
693
|
+
} else {
|
|
694
|
+
assetName = platformArch === "arm64" ? "bun-linux-arm64.zip" : "bun-linux-x64.zip";
|
|
695
|
+
dirName = platformArch === "arm64" ? "bun-linux-arm64" : "bun-linux-x64";
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
const binExt = platformOS === "win" ? ".exe" : "";
|
|
699
|
+
const overrideDir = join(ELECTROBUN_CACHE_PATH, "bunny-bun-override", `${platformOS}-${platformArch}`);
|
|
700
|
+
const overrideBinary = join(overrideDir, `bun${binExt}`);
|
|
701
|
+
const bunUrl = `https://github.com/blackboardsh/bun/releases/download/${releaseTag}/${assetName}`;
|
|
702
|
+
|
|
703
|
+
console.log(`Using Bunny Bun: ${releaseTag}`);
|
|
704
|
+
console.log(`Downloading from: ${bunUrl}`);
|
|
705
|
+
|
|
706
|
+
mkdirSync(overrideDir, { recursive: true });
|
|
707
|
+
const tempZipPath = join(overrideDir, "temp.zip");
|
|
708
|
+
|
|
709
|
+
try {
|
|
710
|
+
const response = await fetch(bunUrl);
|
|
711
|
+
if (!response.ok) {
|
|
712
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const contentLength = response.headers.get("content-length");
|
|
716
|
+
const totalSize = contentLength ? parseInt(contentLength, 10) : 0;
|
|
717
|
+
const fileStream = createWriteStream(tempZipPath);
|
|
718
|
+
let downloadedSize = 0;
|
|
719
|
+
let lastReportedPercent = -1;
|
|
720
|
+
|
|
721
|
+
if (response.body) {
|
|
722
|
+
const reader = response.body.getReader();
|
|
723
|
+
while (true) {
|
|
724
|
+
const { done, value } = await reader.read();
|
|
725
|
+
if (done) break;
|
|
726
|
+
const chunk = Buffer.from(value);
|
|
727
|
+
fileStream.write(chunk);
|
|
728
|
+
downloadedSize += chunk.length;
|
|
729
|
+
if (totalSize > 0) {
|
|
730
|
+
const percent = Math.round((downloadedSize / totalSize) * 100);
|
|
731
|
+
const percentTier = Math.floor(percent / 10) * 10;
|
|
732
|
+
if (percentTier > lastReportedPercent && percentTier <= 100) {
|
|
733
|
+
console.log(` Progress: ${percentTier}% (${Math.round(downloadedSize / 1024 / 1024)}MB/${Math.round(totalSize / 1024 / 1024)}MB)`);
|
|
734
|
+
lastReportedPercent = percentTier;
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
await new Promise((resolve, reject) => {
|
|
741
|
+
fileStream.end((error: any) => { if (error) reject(error); else resolve(void 0); });
|
|
742
|
+
});
|
|
743
|
+
|
|
744
|
+
console.log(`Download completed (${Math.round(downloadedSize / 1024 / 1024)}MB), extracting...`);
|
|
745
|
+
|
|
746
|
+
if (platformOS === "win") {
|
|
747
|
+
execSync(`powershell -command "Expand-Archive -Path '${tempZipPath}' -DestinationPath '${overrideDir}' -Force"`, { stdio: "inherit" });
|
|
748
|
+
} else {
|
|
749
|
+
execSync(`unzip -o ${escapePathForTerminal(tempZipPath)} -d ${escapePathForTerminal(overrideDir)}`, { stdio: "inherit" });
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
// Move binary from extracted subdirectory
|
|
753
|
+
const extractedBinary = join(overrideDir, dirName, `bun${binExt}`);
|
|
754
|
+
if (existsSync(extractedBinary)) {
|
|
755
|
+
renameSync(extractedBinary, overrideBinary);
|
|
756
|
+
} else {
|
|
757
|
+
throw new Error(`Bun binary not found after extraction at ${extractedBinary}`);
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
if (platformOS !== "win") {
|
|
761
|
+
execSync(`chmod +x ${escapePathForTerminal(overrideBinary)}`);
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
// Also extract ICU data if present
|
|
765
|
+
const extractedDir = join(overrideDir, dirName);
|
|
766
|
+
if (existsSync(extractedDir)) {
|
|
767
|
+
for (const file of readdirSync(extractedDir)) {
|
|
768
|
+
if (file.endsWith(".dat")) {
|
|
769
|
+
renameSync(join(extractedDir, file), join(overrideDir, file));
|
|
770
|
+
}
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
writeFileSync(join(overrideDir, ".bun-version"), releaseTag);
|
|
775
|
+
|
|
776
|
+
if (existsSync(tempZipPath)) unlinkSync(tempZipPath);
|
|
777
|
+
if (existsSync(extractedDir)) rmSync(extractedDir, { recursive: true, force: true });
|
|
778
|
+
|
|
779
|
+
console.log(`Bunny Bun ${releaseTag} for ${platformOS}-${platformArch} set up successfully`);
|
|
780
|
+
} catch (error: any) {
|
|
781
|
+
if (existsSync(overrideDir)) {
|
|
782
|
+
try { rmSync(overrideDir, { recursive: true, force: true }); } catch {}
|
|
783
|
+
}
|
|
784
|
+
console.error(`Failed to set up Bunny Bun ${releaseTag} for ${platformOS}-${platformArch}:`, error.message);
|
|
785
|
+
console.error(`\nVerify the release tag exists at: https://github.com/blackboardsh/bun/releases`);
|
|
786
|
+
process.exit(1);
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
|
|
667
790
|
async function ensureCEFDependencies(
|
|
668
791
|
targetOS?: "macos" | "win" | "linux",
|
|
669
792
|
targetArch?: "arm64" | "x64",
|
|
@@ -1357,6 +1480,7 @@ const defaultConfig = {
|
|
|
1357
1480
|
cefVersion: undefined as string | undefined, // Override CEF version: "CEF_VERSION+chromium-CHROMIUM_VERSION"
|
|
1358
1481
|
wgpuVersion: undefined as string | undefined, // Override Dawn (WebGPU) version: "0.2.3" or "v0.2.3-beta.0"
|
|
1359
1482
|
bunVersion: undefined as string | undefined, // Override Bun runtime version: "1.4.2"
|
|
1483
|
+
bunnyBun: undefined as string | undefined, // Use Electrobunny's Bun fork: "bunny-bun-abc1234" (release tag from blackboardsh/bun)
|
|
1360
1484
|
locales: undefined as string[] | "*" | undefined, // ICU locales subset (Linux/Windows)
|
|
1361
1485
|
mac: {
|
|
1362
1486
|
codesign: false,
|
|
@@ -1398,6 +1522,16 @@ const defaultConfig = {
|
|
|
1398
1522
|
copy: undefined as Record<string, string> | undefined,
|
|
1399
1523
|
watch: undefined as string[] | undefined,
|
|
1400
1524
|
watchIgnore: undefined as string[] | undefined,
|
|
1525
|
+
carrot: undefined as {
|
|
1526
|
+
id: string;
|
|
1527
|
+
name: string;
|
|
1528
|
+
description?: string;
|
|
1529
|
+
mode?: "window" | "background";
|
|
1530
|
+
permissions?: Record<string, unknown>;
|
|
1531
|
+
dependencies?: Record<string, string>;
|
|
1532
|
+
remoteUIs?: Record<string, { entrypoint: string; [key: string]: unknown }>;
|
|
1533
|
+
carrotOnly?: boolean;
|
|
1534
|
+
} | undefined,
|
|
1401
1535
|
},
|
|
1402
1536
|
runtime: {} as Record<string, unknown>,
|
|
1403
1537
|
scripts: {
|
|
@@ -2013,21 +2147,38 @@ Categories=Utility;Application;
|
|
|
2013
2147
|
);
|
|
2014
2148
|
}
|
|
2015
2149
|
|
|
2150
|
+
const isCarrotOnly = config.build.carrot?.carrotOnly === true;
|
|
2151
|
+
|
|
2016
2152
|
// build macos bundle
|
|
2017
2153
|
// Use display name (with spaces) for macOS bundle folders, sanitized name for other platforms
|
|
2154
|
+
let appBundleFolderPath: string;
|
|
2155
|
+
let appBundleFolderContentsPath: string;
|
|
2156
|
+
let appBundleMacOSPath: string;
|
|
2157
|
+
let appBundleFolderResourcesPath: string;
|
|
2158
|
+
let appBundleFolderFrameworksPath: string;
|
|
2159
|
+
let appBundleAppCodePath: string;
|
|
2018
2160
|
const bundleName =
|
|
2019
2161
|
targetOS === "macos" ? macOSBundleDisplayName : appFileName;
|
|
2020
|
-
const {
|
|
2021
|
-
appBundleFolderPath,
|
|
2022
|
-
appBundleFolderContentsPath,
|
|
2023
|
-
appBundleMacOSPath,
|
|
2024
|
-
appBundleFolderResourcesPath,
|
|
2025
|
-
appBundleFolderFrameworksPath,
|
|
2026
|
-
} = createAppBundle(bundleName, buildFolder, targetOS);
|
|
2027
|
-
|
|
2028
|
-
const appBundleAppCodePath = join(appBundleFolderResourcesPath, "app");
|
|
2029
2162
|
|
|
2030
|
-
|
|
2163
|
+
if (isCarrotOnly) {
|
|
2164
|
+
// For carrot-only builds, create a minimal output structure for bun/view builds
|
|
2165
|
+
appBundleFolderPath = join(buildFolder, "carrot-build");
|
|
2166
|
+
appBundleFolderContentsPath = appBundleFolderPath;
|
|
2167
|
+
appBundleMacOSPath = appBundleFolderPath;
|
|
2168
|
+
appBundleFolderResourcesPath = appBundleFolderPath;
|
|
2169
|
+
appBundleFolderFrameworksPath = appBundleFolderPath;
|
|
2170
|
+
appBundleAppCodePath = join(appBundleFolderPath, "app");
|
|
2171
|
+
mkdirSync(appBundleAppCodePath, { recursive: true });
|
|
2172
|
+
} else {
|
|
2173
|
+
const bundle = createAppBundle(bundleName, buildFolder, targetOS);
|
|
2174
|
+
appBundleFolderPath = bundle.appBundleFolderPath;
|
|
2175
|
+
appBundleFolderContentsPath = bundle.appBundleFolderContentsPath;
|
|
2176
|
+
appBundleMacOSPath = bundle.appBundleMacOSPath;
|
|
2177
|
+
appBundleFolderResourcesPath = bundle.appBundleFolderResourcesPath;
|
|
2178
|
+
appBundleFolderFrameworksPath = bundle.appBundleFolderFrameworksPath;
|
|
2179
|
+
appBundleAppCodePath = join(appBundleFolderResourcesPath, "app");
|
|
2180
|
+
mkdirSync(appBundleAppCodePath, { recursive: true });
|
|
2181
|
+
}
|
|
2031
2182
|
|
|
2032
2183
|
// const bundledBunPath = join(appBundleMacOSPath, 'bun');
|
|
2033
2184
|
// cpSync(bunPath, bundledBunPath);
|
|
@@ -2038,6 +2189,10 @@ Categories=Utility;Application;
|
|
|
2038
2189
|
|
|
2039
2190
|
// We likely want to let users configure this for different environments (eg: dev, canary, stable) and/or
|
|
2040
2191
|
// provide methods to help segment data in those folders based on channel/environment
|
|
2192
|
+
|
|
2193
|
+
let InfoPlistContents = "";
|
|
2194
|
+
|
|
2195
|
+
if (!isCarrotOnly) {
|
|
2041
2196
|
// Generate usage descriptions from entitlements
|
|
2042
2197
|
const usageDescriptions = generateUsageDescriptions(
|
|
2043
2198
|
config.build.mac.entitlements || {},
|
|
@@ -2048,7 +2203,7 @@ Categories=Utility;Application;
|
|
|
2048
2203
|
config.app.identifier,
|
|
2049
2204
|
);
|
|
2050
2205
|
|
|
2051
|
-
|
|
2206
|
+
InfoPlistContents = `<?xml version="1.0" encoding="UTF-8"?>
|
|
2052
2207
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
2053
2208
|
<plist version="1.0">
|
|
2054
2209
|
<dict>
|
|
@@ -2191,6 +2346,7 @@ Categories=Utility;Application;
|
|
|
2191
2346
|
currentTarget.os,
|
|
2192
2347
|
currentTarget.arch,
|
|
2193
2348
|
config.build.bunVersion,
|
|
2349
|
+
config.build.bunnyBun,
|
|
2194
2350
|
);
|
|
2195
2351
|
// Note: .bin/bun binary in node_modules is a symlink to the versioned one in another place
|
|
2196
2352
|
// in node_modules, so we have to dereference here to get the actual binary in the bundle.
|
|
@@ -2788,6 +2944,7 @@ Categories=Utility;Application;
|
|
|
2788
2944
|
});
|
|
2789
2945
|
}
|
|
2790
2946
|
}
|
|
2947
|
+
} // end if (!isCarrotOnly)
|
|
2791
2948
|
|
|
2792
2949
|
// transpile developer's bun code
|
|
2793
2950
|
const bunDestFolder = join(appBundleAppCodePath, "bun");
|
|
@@ -2874,10 +3031,112 @@ Categories=Utility;Application;
|
|
|
2874
3031
|
cpSync(source, destination, { recursive: true, dereference: true });
|
|
2875
3032
|
}
|
|
2876
3033
|
|
|
2877
|
-
|
|
3034
|
+
if (!isCarrotOnly) {
|
|
3035
|
+
buildIcons(appBundleFolderResourcesPath, appBundleFolderPath);
|
|
3036
|
+
}
|
|
2878
3037
|
|
|
2879
|
-
//
|
|
2880
|
-
|
|
3038
|
+
// Build carrot artifact if configured (before postBuild so the hook can add custom views)
|
|
3039
|
+
let carrotBuildDir: string | null = null;
|
|
3040
|
+
if (config.build.carrot) {
|
|
3041
|
+
const carrotConfig = config.build.carrot;
|
|
3042
|
+
carrotBuildDir = join(buildFolder, "carrot", carrotConfig.id);
|
|
3043
|
+
|
|
3044
|
+
if (existsSync(carrotBuildDir)) {
|
|
3045
|
+
rmSync(carrotBuildDir, { recursive: true });
|
|
3046
|
+
}
|
|
3047
|
+
mkdirSync(carrotBuildDir, { recursive: true });
|
|
3048
|
+
|
|
3049
|
+
// Copy the bun bundle as worker.js
|
|
3050
|
+
const bunOutputDir = join(appBundleAppCodePath, "bun");
|
|
3051
|
+
// The output filename matches the entrypoint name (e.g., worker.ts → worker.js)
|
|
3052
|
+
const bunEntryName = basename(config.build.bun.entrypoint).replace(/\.ts$/, ".js");
|
|
3053
|
+
const workerSrc = join(bunOutputDir, bunEntryName);
|
|
3054
|
+
if (existsSync(workerSrc)) {
|
|
3055
|
+
cpSync(workerSrc, join(carrotBuildDir, "worker.js"));
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
// Copy views
|
|
3059
|
+
const viewsSrc = join(appBundleAppCodePath, "views");
|
|
3060
|
+
if (existsSync(viewsSrc)) {
|
|
3061
|
+
const viewsDest = join(carrotBuildDir, "views");
|
|
3062
|
+
cpSync(viewsSrc, viewsDest, { recursive: true });
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
// Copy static assets
|
|
3066
|
+
for (const relSource in config.build.copy) {
|
|
3067
|
+
const destRel = config.build.copy[relSource]!;
|
|
3068
|
+
const builtAsset = join(appBundleAppCodePath, destRel);
|
|
3069
|
+
if (existsSync(builtAsset)) {
|
|
3070
|
+
const carrotDest = join(carrotBuildDir, destRel);
|
|
3071
|
+
mkdirSync(dirname(carrotDest), { recursive: true });
|
|
3072
|
+
cpSync(builtAsset, carrotDest, { recursive: true });
|
|
3073
|
+
}
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
// Build remote UIs if configured
|
|
3077
|
+
if (carrotConfig.remoteUIs) {
|
|
3078
|
+
for (const remoteUIName in carrotConfig.remoteUIs) {
|
|
3079
|
+
const remoteUIConfig = carrotConfig.remoteUIs[remoteUIName]!;
|
|
3080
|
+
const remoteUISource = join(projectRoot, remoteUIConfig.entrypoint);
|
|
3081
|
+
if (!existsSync(remoteUISource)) {
|
|
3082
|
+
console.error(`Remote UI entrypoint not found: ${remoteUISource}`);
|
|
3083
|
+
continue;
|
|
3084
|
+
}
|
|
3085
|
+
const remoteUIDestFolder = join(carrotBuildDir, "remote-ui", remoteUIName);
|
|
3086
|
+
mkdirSync(remoteUIDestFolder, { recursive: true });
|
|
3087
|
+
|
|
3088
|
+
const { entrypoint: _entrypoint, ...remoteUIBuildOptions } = remoteUIConfig;
|
|
3089
|
+
const remoteUIBuildResult = await Bun.build({
|
|
3090
|
+
...remoteUIBuildOptions,
|
|
3091
|
+
entrypoints: [remoteUISource],
|
|
3092
|
+
outdir: remoteUIDestFolder,
|
|
3093
|
+
target: "browser",
|
|
3094
|
+
});
|
|
3095
|
+
|
|
3096
|
+
if (!remoteUIBuildResult.success) {
|
|
3097
|
+
console.error(`Failed to build remote UI: ${remoteUIName}`);
|
|
3098
|
+
printBuildLogs(remoteUIBuildResult.logs);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
|
|
3103
|
+
// Write carrot.json manifest
|
|
3104
|
+
const carrotManifest = {
|
|
3105
|
+
id: carrotConfig.id,
|
|
3106
|
+
name: carrotConfig.name,
|
|
3107
|
+
version: config.app.version,
|
|
3108
|
+
description: carrotConfig.description || config.app.description || "",
|
|
3109
|
+
mode: carrotConfig.mode || "window",
|
|
3110
|
+
permissions: carrotConfig.permissions || {},
|
|
3111
|
+
dependencies: carrotConfig.dependencies || {},
|
|
3112
|
+
worker: { relativePath: "worker.js" },
|
|
3113
|
+
view: existsSync(viewsSrc) ? { relativePath: "views/index.html" } : undefined,
|
|
3114
|
+
};
|
|
3115
|
+
writeFileSync(
|
|
3116
|
+
join(carrotBuildDir, "carrot.json"),
|
|
3117
|
+
JSON.stringify(carrotManifest, null, 2),
|
|
3118
|
+
);
|
|
3119
|
+
|
|
3120
|
+
console.log(`Carrot built: ${carrotConfig.id} v${config.app.version}`);
|
|
3121
|
+
}
|
|
3122
|
+
|
|
3123
|
+
// Run postBuild script — with carrot dir available if configured
|
|
3124
|
+
runHook("postBuild", carrotBuildDir ? { ELECTROBUN_CARROT_DIR: carrotBuildDir } : {});
|
|
3125
|
+
|
|
3126
|
+
// Compress carrot artifact for non-dev builds
|
|
3127
|
+
if (config.build.carrot && carrotBuildDir && buildEnvironment !== "dev") {
|
|
3128
|
+
const artifactName = `${config.build.carrot.id}-${config.app.version}.tar.zst`;
|
|
3129
|
+
mkdirSync(artifactFolder, { recursive: true });
|
|
3130
|
+
const artifactPath = join(artifactFolder, artifactName);
|
|
3131
|
+
|
|
3132
|
+
execSync(`tar -C "${carrotBuildDir}" -cf - . | zstd -o "${artifactPath}"`, { stdio: "pipe" });
|
|
3133
|
+
const size = statSync(artifactPath).size;
|
|
3134
|
+
console.log(`Carrot artifact: ${artifactPath} (${(size / 1024).toFixed(0)} KB)`);
|
|
3135
|
+
}
|
|
3136
|
+
|
|
3137
|
+
if (isCarrotOnly) {
|
|
3138
|
+
return;
|
|
3139
|
+
}
|
|
2881
3140
|
|
|
2882
3141
|
// Pack app resources into ASAR archive if enabled
|
|
2883
3142
|
if (config.build.useAsar) {
|
|
@@ -3113,6 +3372,7 @@ Categories=Utility;Application;
|
|
|
3113
3372
|
? { cefVersion: config.build?.cefVersion ?? DEFAULT_CEF_VERSION_STRING }
|
|
3114
3373
|
: {}),
|
|
3115
3374
|
bunVersion: config.build?.bunVersion ?? BUN_VERSION,
|
|
3375
|
+
...(config.build?.bunnyBun ? { bunnyBun: config.build.bunnyBun } : {}),
|
|
3116
3376
|
};
|
|
3117
3377
|
|
|
3118
3378
|
// Include chromiumFlags only if the developer defined them
|