electrobun 0.0.19-beta.72 → 0.0.19-beta.73

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.
@@ -341,9 +341,22 @@ const Updater = {
341
341
  }
342
342
 
343
343
  // Note: resolve here removes the extra trailing / that the tar file adds
344
- const newAppBundlePath = resolve(
344
+ const extractedAppPath = resolve(
345
345
  join(extractionFolder, appBundleSubpath)
346
346
  );
347
+
348
+ // On Linux, we need to move the app from self-extraction to the app directory
349
+ let newAppBundlePath: string;
350
+ if (currentOS === 'linux') {
351
+ // Get the parent directory (one level up from self-extraction)
352
+ const parentDir = resolve(extractionFolder, "..");
353
+ newAppBundlePath = join(parentDir, "app_new");
354
+
355
+ // Move the extracted app to a temporary location
356
+ renameSync(extractedAppPath, newAppBundlePath);
357
+ } else {
358
+ newAppBundlePath = extractedAppPath;
359
+ }
347
360
  // Platform-specific app path calculation
348
361
  let runningAppBundlePath: string;
349
362
  if (currentOS === 'macos') {
@@ -353,23 +366,50 @@ const Updater = {
353
366
  "..",
354
367
  ".."
355
368
  );
369
+ } else if (currentOS === 'linux') {
370
+ // On Linux, executable is at app/bin/launcher
371
+ runningAppBundlePath = resolve(
372
+ dirname(process.execPath),
373
+ "..",
374
+ ".."
375
+ );
356
376
  } else {
357
- // On Windows/Linux, the executable is the app itself
377
+ // On Windows, the executable is the app itself
358
378
  runningAppBundlePath = process.execPath;
359
379
  }
360
- // Platform-specific backup naming
361
- const backupName = currentOS === 'macos' ? "backup.app" : "backup";
362
- const backupAppBundlePath = join(extractionFolder, backupName);
380
+ // Platform-specific backup naming and location
381
+ let backupAppBundlePath: string;
382
+ if (currentOS === 'linux') {
383
+ // On Linux, keep backup in self-extraction folder
384
+ backupAppBundlePath = join(extractionFolder, "backup");
385
+ } else {
386
+ // On macOS/Windows, backup in extraction folder
387
+ const backupName = currentOS === 'macos' ? "backup.app" : "backup";
388
+ backupAppBundlePath = join(extractionFolder, backupName);
389
+ }
363
390
 
364
391
  try {
365
- // const backupState = statSync(backupAppBundlePath);
392
+ // Remove existing backup if it exists
366
393
  if (statSync(backupAppBundlePath, { throwIfNoEntry: false })) {
367
394
  rmdirSync(backupAppBundlePath, { recursive: true });
368
395
  } else {
369
396
  console.log("backupAppBundlePath does not exist");
370
397
  }
398
+
399
+ // Move current running app to backup
371
400
  renameSync(runningAppBundlePath, backupAppBundlePath);
401
+
402
+ // Move new app to running location
372
403
  renameSync(newAppBundlePath, runningAppBundlePath);
404
+
405
+ // On Linux, clean up the temporary app_new if it wasn't already moved
406
+ if (currentOS === 'linux') {
407
+ try {
408
+ rmdirSync(newAppBundlePath, { recursive: true });
409
+ } catch {
410
+ // Ignore if already moved
411
+ }
412
+ }
373
413
  } catch (error) {
374
414
  console.error("Failed to replace app with new version", error);
375
415
  return;
@@ -247,11 +247,14 @@ export const native = (() => {
247
247
  // },
248
248
  });
249
249
  } catch (err) {
250
- console.log('FATAL Error opening native FFI', err);
250
+ console.log('FATAL Error opening native FFI:', err.message);
251
251
  console.log('This may be due to:');
252
252
  console.log(' - Missing libNativeWrapper.dll/so/dylib');
253
253
  console.log(' - Architecture mismatch (ARM64 vs x64)');
254
254
  console.log(' - Missing WebView2 or CEF dependencies');
255
+ if (suffix === 'so') {
256
+ console.log(' - Missing system libraries (try: ldd ./libNativeWrapper.so)');
257
+ }
255
258
  console.log('Check that the build process completed successfully for your architecture.');
256
259
  process.exit();
257
260
  }
package/dist/main.js CHANGED
@@ -1,12 +1,53 @@
1
1
  // @bun
2
+ var __require = import.meta.require;
3
+
2
4
  // src/launcher/main.ts
3
- import { join, dirname } from "path";
5
+ import { join, dirname, resolve } from "path";
4
6
  import { dlopen, suffix } from "bun:ffi";
5
- var lib = dlopen(`./libNativeWrapper.${suffix}`, {
6
- runNSApplication: { args: [], returns: "void" }
7
- });
8
- var pathToLauncherBin = process.argv0;
9
- var pathToMacOS = dirname(pathToLauncherBin);
10
- var appEntrypointPath = join(pathToMacOS, "..", "Resources", "app", "bun", "index.js");
11
- new Worker(appEntrypointPath, {});
12
- lib.symbols.runNSApplication();
7
+ import { existsSync } from "fs";
8
+ var libPath = `./libNativeWrapper.${suffix}`;
9
+ var absoluteLibPath = resolve(libPath);
10
+ function main() {
11
+ if (process.platform === "linux") {
12
+ const cefLibs = ["./libcef.so", "./libvk_swiftshader.so"];
13
+ const existingCefLibs = cefLibs.filter((lib2) => existsSync(lib2));
14
+ if (existingCefLibs.length > 0 && !process.env.LD_PRELOAD) {
15
+ console.error(`[LAUNCHER] ERROR: CEF libraries found but LD_PRELOAD not set!`);
16
+ console.error(`[LAUNCHER] Please run through the wrapper script: ./run.sh`);
17
+ console.error(`[LAUNCHER] Or set: LD_PRELOAD="${existingCefLibs.join(":")}" before starting.`);
18
+ const { spawn } = __require("child_process");
19
+ const env = { ...process.env, LD_PRELOAD: existingCefLibs.join(":") };
20
+ const child = spawn(process.argv[0], process.argv.slice(1), {
21
+ env,
22
+ stdio: "inherit"
23
+ });
24
+ child.on("exit", (code) => process.exit(code));
25
+ return;
26
+ }
27
+ }
28
+ let lib;
29
+ try {
30
+ if (!process.env.LD_LIBRARY_PATH?.includes(".")) {
31
+ process.env.LD_LIBRARY_PATH = `.${process.env.LD_LIBRARY_PATH ? ":" + process.env.LD_LIBRARY_PATH : ""}`;
32
+ }
33
+ lib = dlopen(libPath, {
34
+ runNSApplication: { args: [], returns: "void" }
35
+ });
36
+ } catch (error) {
37
+ console.error(`[LAUNCHER] Failed to load library: ${error.message}`);
38
+ try {
39
+ lib = dlopen(absoluteLibPath, {
40
+ runNSApplication: { args: [], returns: "void" }
41
+ });
42
+ } catch (absError) {
43
+ console.error(`[LAUNCHER] Library loading failed. Try running: ldd ${libPath}`);
44
+ throw error;
45
+ }
46
+ }
47
+ const pathToLauncherBin = process.argv0;
48
+ const pathToMacOS = dirname(pathToLauncherBin);
49
+ const appEntrypointPath = join(pathToMacOS, "..", "Resources", "app", "bun", "index.js");
50
+ new Worker(appEntrypointPath, {});
51
+ lib.symbols.runNSApplication();
52
+ }
53
+ main();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "electrobun",
3
- "version": "0.0.19-beta.72",
3
+ "version": "0.0.19-beta.73",
4
4
  "description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
5
5
  "license": "MIT",
6
6
  "author": "Blackboard Technologies Inc.",
package/src/cli/index.ts CHANGED
@@ -9,6 +9,8 @@ import {
9
9
  createWriteStream,
10
10
  unlinkSync,
11
11
  readdirSync,
12
+ rmSync,
13
+ symlinkSync,
12
14
  } from "fs";
13
15
  import { execSync } from "child_process";
14
16
  import tar from "tar";
@@ -400,6 +402,12 @@ const defaultConfig = {
400
402
  },
401
403
  icons: "icon.iconset",
402
404
  },
405
+ win: {
406
+ bundleCEF: false,
407
+ },
408
+ linux: {
409
+ bundleCEF: false,
410
+ },
403
411
  bun: {
404
412
  entrypoint: "src/bun/index.ts",
405
413
  external: [],
@@ -432,7 +440,7 @@ const validEnvironments = ["dev", "canary", "stable"];
432
440
 
433
441
  // todo (yoav): dev, canary, and stable;
434
442
  const buildEnvironment: "dev" | "canary" | "stable" =
435
- validEnvironments.includes(envArg) ? envArg : "dev";
443
+ validEnvironments.includes(envArg || "dev") ? (envArg || "dev") : "dev";
436
444
 
437
445
  // Determine build targets
438
446
  type BuildTarget = { os: 'macos' | 'win' | 'linux', arch: 'arm64' | 'x64' };
@@ -1046,11 +1054,13 @@ if (commandArg === "init") {
1046
1054
  'libvulkan.so.1'
1047
1055
  ];
1048
1056
 
1057
+ // Copy CEF .so files to main directory as symlinks to cef/ subdirectory
1049
1058
  cefSoFiles.forEach(soFile => {
1050
1059
  const sourcePath = join(cefSourcePath, soFile);
1051
1060
  const destPath = join(appBundleMacOSPath, soFile);
1052
1061
  if (existsSync(sourcePath)) {
1053
- cpSync(sourcePath, destPath);
1062
+ // We'll create the actual file in cef/ and symlink from main directory
1063
+ // This will be done after the cef/ directory is populated
1054
1064
  }
1055
1065
  });
1056
1066
 
@@ -1112,6 +1122,30 @@ if (commandArg === "init") {
1112
1122
  }
1113
1123
  });
1114
1124
 
1125
+ // Create symlinks from main directory to cef/ subdirectory for .so files
1126
+ console.log('Creating symlinks for CEF libraries...');
1127
+ cefSoFiles.forEach(soFile => {
1128
+ const cefFilePath = join(cefResourcesDestination, soFile);
1129
+ const mainDirPath = join(appBundleMacOSPath, soFile);
1130
+
1131
+ if (existsSync(cefFilePath)) {
1132
+ try {
1133
+ // Remove any existing file/symlink in main directory
1134
+ if (existsSync(mainDirPath)) {
1135
+ rmSync(mainDirPath);
1136
+ }
1137
+ // Create symlink from main directory to cef/ subdirectory
1138
+ symlinkSync(join('cef', soFile), mainDirPath);
1139
+ console.log(`Created symlink for CEF library: ${soFile} -> cef/${soFile}`);
1140
+ } catch (error) {
1141
+ console.log(`WARNING: Failed to create symlink for ${soFile}: ${error}`);
1142
+ // Fallback to copying the file
1143
+ cpSync(cefFilePath, mainDirPath);
1144
+ console.log(`Fallback: Copied CEF library to main directory: ${soFile}`);
1145
+ }
1146
+ }
1147
+ });
1148
+
1115
1149
  // Copy CEF helper processes with different names
1116
1150
  const cefHelperNames = [
1117
1151
  "bun Helper",
@@ -1352,7 +1386,7 @@ if (commandArg === "init") {
1352
1386
  // zstd is the clear winner here. dev iteration speed gain of 1min 15s per build is much more valubale
1353
1387
  // than saving 1 more MB of space/bandwidth.
1354
1388
 
1355
- const compressedTarPath = `${tarPath}.zst`;
1389
+ let compressedTarPath = `${tarPath}.zst`;
1356
1390
  artifactsToUpload.push(compressedTarPath);
1357
1391
 
1358
1392
  // zstd compress tarball
@@ -1365,11 +1399,10 @@ if (commandArg === "init") {
1365
1399
  const useStream = tarball.size > 100 * 1024 * 1024;
1366
1400
 
1367
1401
  if (tarball.size > 0) {
1368
- // Uint8 array filestream of the tar file
1369
-
1402
+ // Uint8 array filestream of the tar file
1370
1403
  const data = new Uint8Array(tarBuffer);
1371
1404
 
1372
- const compressionLevel = 22;
1405
+ const compressionLevel = 22; // Maximum compression - now safe with stripped CEF libraries
1373
1406
  const compressedData = ZstdSimple.compress(data, compressionLevel);
1374
1407
 
1375
1408
  console.log(
@@ -1461,9 +1494,68 @@ if (commandArg === "init") {
1461
1494
  // Copy the self-extracting bundle to platform-specific filename
1462
1495
  if (targetOS === 'win') {
1463
1496
  // On Windows, create a self-extracting exe
1464
- // For now, just copy the bundle folder
1465
- artifactsToUpload.push(compressedTarPath);
1497
+ const selfExtractingExePath = await createWindowsSelfExtractingExe(
1498
+ buildFolder,
1499
+ compressedTarPath,
1500
+ appFileName,
1501
+ targetPaths,
1502
+ buildEnvironment
1503
+ );
1504
+ artifactsToUpload.push(selfExtractingExePath);
1466
1505
  } else if (targetOS === 'linux') {
1506
+ // Create desktop file for Linux
1507
+ const desktopFileContent = `[Desktop Entry]
1508
+ Version=1.0
1509
+ Type=Application
1510
+ Name=${config.package?.name || config.app.name}
1511
+ Comment=${config.package?.description || config.app.description || ''}
1512
+ Exec=${appFileName}
1513
+ Icon=${appFileName}
1514
+ Terminal=false
1515
+ StartupWMClass=${appFileName}
1516
+ Categories=Application;
1517
+ `;
1518
+
1519
+ const desktopFilePath = join(appBundleFolderPath, `${appFileName}.desktop`);
1520
+ writeFileSync(desktopFilePath, desktopFileContent);
1521
+
1522
+ // Make desktop file executable
1523
+ execSync(`chmod +x ${escapePathForTerminal(desktopFilePath)}`);
1524
+
1525
+ // Create user-friendly launcher script
1526
+ const launcherScriptContent = `#!/bin/bash
1527
+ # ${config.package?.name || config.app.name} Launcher
1528
+ # This script launches the application from any location
1529
+
1530
+ # Get the directory where this script is located
1531
+ SCRIPT_DIR="$(cd "$(dirname "\${BASH_SOURCE[0]}")" && pwd)"
1532
+
1533
+ # Find the launcher binary relative to this script
1534
+ LAUNCHER_BINARY="\$SCRIPT_DIR/bin/launcher"
1535
+
1536
+ if [ ! -x "\$LAUNCHER_BINARY" ]; then
1537
+ echo "Error: Could not find launcher binary at \$LAUNCHER_BINARY"
1538
+ exit 1
1539
+ fi
1540
+
1541
+ # Launch the application
1542
+ exec "\$LAUNCHER_BINARY" "\$@"
1543
+ `;
1544
+
1545
+ const launcherScriptPath = join(appBundleFolderPath, `${appFileName}.sh`);
1546
+ writeFileSync(launcherScriptPath, launcherScriptContent);
1547
+ execSync(`chmod +x ${escapePathForTerminal(launcherScriptPath)}`);
1548
+
1549
+ // Create self-extracting Linux binary (similar to Windows approach)
1550
+ const selfExtractingLinuxPath = await createLinuxSelfExtractingBinary(
1551
+ buildFolder,
1552
+ compressedTarPath,
1553
+ appFileName,
1554
+ targetPaths,
1555
+ buildEnvironment
1556
+ );
1557
+ artifactsToUpload.push(selfExtractingLinuxPath);
1558
+
1467
1559
  // On Linux, create a tar.gz of the bundle
1468
1560
  const linuxTarPath = join(buildFolder, `${appFileName}.tar.gz`);
1469
1561
  execSync(`tar -czf ${escapePathForTerminal(linuxTarPath)} -C ${escapePathForTerminal(buildFolder)} ${escapePathForTerminal(basename(appBundleFolderPath))}`);
@@ -1765,6 +1857,193 @@ function getEntitlementValue(value: boolean | string) {
1765
1857
  }
1766
1858
  }
1767
1859
 
1860
+ async function createWindowsSelfExtractingExe(
1861
+ buildFolder: string,
1862
+ compressedTarPath: string,
1863
+ appFileName: string,
1864
+ targetPaths: any,
1865
+ buildEnvironment: string
1866
+ ): Promise<string> {
1867
+ console.log("Creating self-extracting Windows exe...");
1868
+
1869
+ // Format: MyApp-Setup.exe (stable) or MyApp-Setup-canary.exe (non-stable)
1870
+ const setupFileName = buildEnvironment === "stable"
1871
+ ? `${config.app.name}-Setup.exe`
1872
+ : `${config.app.name}-Setup-${buildEnvironment}.exe`;
1873
+
1874
+ const outputExePath = join(buildFolder, setupFileName);
1875
+
1876
+ // Read the extractor exe
1877
+ const extractorExe = readFileSync(targetPaths.EXTRACTOR);
1878
+
1879
+ // Read the compressed archive
1880
+ const compressedArchive = readFileSync(compressedTarPath);
1881
+
1882
+ // Create metadata JSON
1883
+ const metadata = {
1884
+ identifier: config.app.identifier,
1885
+ name: config.app.name,
1886
+ channel: buildEnvironment
1887
+ };
1888
+ const metadataJson = JSON.stringify(metadata);
1889
+ const metadataBuffer = Buffer.from(metadataJson, 'utf8');
1890
+
1891
+ // Create marker buffers
1892
+ const metadataMarker = Buffer.from('ELECTROBUN_METADATA_V1', 'utf8');
1893
+ const archiveMarker = Buffer.from('ELECTROBUN_ARCHIVE_V1', 'utf8');
1894
+
1895
+ // Combine extractor + metadata marker + metadata + archive marker + archive
1896
+ const combinedBuffer = Buffer.concat([
1897
+ extractorExe,
1898
+ metadataMarker,
1899
+ metadataBuffer,
1900
+ archiveMarker,
1901
+ compressedArchive
1902
+ ]);
1903
+
1904
+ // Write the self-extracting exe
1905
+ writeFileSync(outputExePath, combinedBuffer);
1906
+
1907
+ // Make it executable (though Windows doesn't need chmod)
1908
+ if (OS !== 'win') {
1909
+ execSync(`chmod +x ${escapePathForTerminal(outputExePath)}`);
1910
+ }
1911
+
1912
+ console.log(`Created self-extracting exe: ${outputExePath} (${(combinedBuffer.length / 1024 / 1024).toFixed(2)} MB)`);
1913
+
1914
+ return outputExePath;
1915
+ }
1916
+
1917
+ async function createLinuxSelfExtractingBinary(
1918
+ buildFolder: string,
1919
+ compressedTarPath: string,
1920
+ appFileName: string,
1921
+ targetPaths: any,
1922
+ buildEnvironment: string
1923
+ ): Promise<string> {
1924
+ console.log("Creating self-extracting Linux binary...");
1925
+
1926
+ // Format: MyApp-Setup.run (stable) or MyApp-Setup-canary.run (non-stable)
1927
+ const setupFileName = buildEnvironment === "stable"
1928
+ ? `${config.app.name}-Setup.run`
1929
+ : `${config.app.name}-Setup-${buildEnvironment}.run`;
1930
+
1931
+ const outputPath = join(buildFolder, setupFileName);
1932
+
1933
+ // Read the extractor binary
1934
+ const extractorBinary = readFileSync(targetPaths.EXTRACTOR);
1935
+
1936
+ // Read the compressed archive
1937
+ const compressedArchive = readFileSync(compressedTarPath);
1938
+
1939
+ // Create metadata JSON
1940
+ const metadata = {
1941
+ identifier: config.app.identifier,
1942
+ name: config.app.name,
1943
+ channel: buildEnvironment
1944
+ };
1945
+ const metadataJson = JSON.stringify(metadata);
1946
+ const metadataBuffer = Buffer.from(metadataJson, 'utf8');
1947
+
1948
+ // Create marker buffers
1949
+ const metadataMarker = Buffer.from('ELECTROBUN_METADATA_V1', 'utf8');
1950
+ const archiveMarker = Buffer.from('ELECTROBUN_ARCHIVE_V1', 'utf8');
1951
+
1952
+ // Combine extractor + metadata marker + metadata + archive marker + archive
1953
+ const combinedBuffer = Buffer.concat([
1954
+ extractorBinary,
1955
+ metadataMarker,
1956
+ metadataBuffer,
1957
+ archiveMarker,
1958
+ compressedArchive
1959
+ ]);
1960
+
1961
+ // Write the self-extracting binary
1962
+ writeFileSync(outputPath, combinedBuffer, { mode: 0o755 });
1963
+
1964
+ // Ensure it's executable (redundant but explicit)
1965
+ execSync(`chmod +x ${escapePathForTerminal(outputPath)}`);
1966
+
1967
+ console.log(`Created self-extracting Linux binary: ${outputPath} (${(combinedBuffer.length / 1024 / 1024).toFixed(2)} MB)`);
1968
+
1969
+ return outputPath;
1970
+ }
1971
+
1972
+ async function createAppImage(buildFolder: string, appBundlePath: string, appFileName: string, config: any): Promise<string | null> {
1973
+ try {
1974
+ console.log("Creating AppImage...");
1975
+
1976
+ // Create AppDir structure
1977
+ const appDirPath = join(buildFolder, `${appFileName}.AppDir`);
1978
+ mkdirSync(appDirPath, { recursive: true });
1979
+
1980
+ // Copy app bundle contents to AppDir
1981
+ const appDirAppPath = join(appDirPath, "app");
1982
+ cpSync(appBundlePath, appDirAppPath, { recursive: true });
1983
+
1984
+ // Create AppRun script (main executable for AppImage)
1985
+ const appRunContent = `#!/bin/bash
1986
+ HERE="$(dirname "$(readlink -f "\${0}")")"
1987
+ export APPDIR="\$HERE"
1988
+ cd "\$HERE"
1989
+ exec "\$HERE/app/bin/launcher" "\$@"
1990
+ `;
1991
+
1992
+ const appRunPath = join(appDirPath, "AppRun");
1993
+ writeFileSync(appRunPath, appRunContent);
1994
+ execSync(`chmod +x ${escapePathForTerminal(appRunPath)}`);
1995
+
1996
+ // Create desktop file in AppDir root
1997
+ const desktopContent = `[Desktop Entry]
1998
+ Version=1.0
1999
+ Type=Application
2000
+ Name=${config.package?.name || config.app.name}
2001
+ Comment=${config.package?.description || config.app.description || ''}
2002
+ Exec=AppRun
2003
+ Icon=${appFileName}
2004
+ Terminal=false
2005
+ StartupWMClass=${appFileName}
2006
+ Categories=Application;
2007
+ `;
2008
+
2009
+ const appDirDesktopPath = join(appDirPath, `${appFileName}.desktop`);
2010
+ writeFileSync(appDirDesktopPath, desktopContent);
2011
+
2012
+ // Copy icon if it exists
2013
+ const iconPath = config.build.linux?.appImageIcon;
2014
+ if (iconPath && existsSync(iconPath)) {
2015
+ const iconDestPath = join(appDirPath, `${appFileName}.png`);
2016
+ cpSync(iconPath, iconDestPath);
2017
+ }
2018
+
2019
+ // Try to create AppImage using available tools
2020
+ const appImagePath = join(buildFolder, `${appFileName}.AppImage`);
2021
+
2022
+ // Check for appimagetool
2023
+ try {
2024
+ execSync('which appimagetool', { stdio: 'pipe' });
2025
+ console.log("Using appimagetool to create AppImage...");
2026
+ execSync(`appimagetool ${escapePathForTerminal(appDirPath)} ${escapePathForTerminal(appImagePath)}`, { stdio: 'inherit' });
2027
+ return appImagePath;
2028
+ } catch {
2029
+ // Check for Docker
2030
+ try {
2031
+ execSync('which docker', { stdio: 'pipe' });
2032
+ console.log("Using Docker to create AppImage...");
2033
+ execSync(`docker run --rm -v "${buildFolder}:/workspace" linuxserver/appimagetool "/workspace/${basename(appDirPath)}" "/workspace/${basename(appImagePath)}"`, { stdio: 'inherit' });
2034
+ return appImagePath;
2035
+ } catch {
2036
+ console.warn("Neither appimagetool nor Docker found. AppImage creation skipped.");
2037
+ console.warn("To create AppImages, install appimagetool or Docker.");
2038
+ return null;
2039
+ }
2040
+ }
2041
+ } catch (error) {
2042
+ console.error("Failed to create AppImage:", error);
2043
+ return null;
2044
+ }
2045
+ }
2046
+
1768
2047
  function codesignAppBundle(
1769
2048
  appBundleOrDmgPath: string,
1770
2049
  entitlementsFilePath?: string
@@ -1,12 +1,18 @@
1
1
  {
2
2
  "app": {
3
- "name": "hellow-world",
3
+ "name": "hello-world",
4
4
  "identifier": "helloworld.electrobun.dev",
5
5
  "version": "0.0.1"
6
6
  },
7
7
  "build": {
8
- "mac": {
9
- "bundleCEF": false
8
+ "mac": {
9
+ "bundleCEF": true
10
+ },
11
+ "linux": {
12
+ "bundleCEF": true
13
+ },
14
+ "win": {
15
+ "bundleCEF": true
10
16
  }
11
17
  },
12
18
  }