electrobun 0.0.19-beta.70 → 0.0.19-beta.72
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/debug.js +5 -0
- package/dist/api/bun/core/Updater.ts +83 -24
- package/dist/api/shared/platform.ts +48 -0
- package/package.json +1 -1
- package/src/cli/index.ts +66 -55
- package/templates/hello-world/README.md +57 -0
- package/templates/hello-world/bun.lock +63 -0
- package/templates/hello-world/electrobun.config +12 -0
- package/templates/hello-world/package.json +16 -0
- package/templates/hello-world/src/bun/index.ts +15 -0
- package/templates/hello-world/src/mainview/index.css +124 -0
- package/templates/hello-world/src/mainview/index.html +47 -0
- package/templates/hello-world/src/mainview/index.ts +5 -0
package/debug.js
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
console.log('process.argv:', process.argv);
|
|
2
|
+
const indexOfElectrobun = process.argv.findIndex((arg) => arg.includes('electrobun'));
|
|
3
|
+
console.log('indexOfElectrobun:', indexOfElectrobun);
|
|
4
|
+
const commandArg = process.argv[indexOfElectrobun + 1] || 'build';
|
|
5
|
+
console.log('commandArg:', commandArg);
|
|
@@ -1,10 +1,26 @@
|
|
|
1
1
|
import { join, dirname, resolve } from "path";
|
|
2
|
-
import { homedir
|
|
2
|
+
import { homedir } from "os";
|
|
3
3
|
import { renameSync, unlinkSync, mkdirSync, rmdirSync, statSync } from "fs";
|
|
4
4
|
import tar from "tar";
|
|
5
5
|
import { ZstdInit } from "@oneidentity/zstd-js/wasm";
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { OS as currentOS, ARCH as currentArch } from '../../shared/platform';
|
|
7
|
+
|
|
8
|
+
// Cross-platform app data directory
|
|
9
|
+
function getAppDataDir(): string {
|
|
10
|
+
switch (currentOS) {
|
|
11
|
+
case 'macos':
|
|
12
|
+
return join(homedir(), "Library", "Application Support");
|
|
13
|
+
case 'win':
|
|
14
|
+
// Use APPDATA environment variable or fallback to default location
|
|
15
|
+
return process.env.APPDATA || join(homedir(), "AppData", "Roaming");
|
|
16
|
+
case 'linux':
|
|
17
|
+
// Use XDG_CONFIG_HOME or fallback to ~/.config
|
|
18
|
+
return process.env.XDG_CONFIG_HOME || join(homedir(), ".config");
|
|
19
|
+
default:
|
|
20
|
+
// Fallback to home directory with .config
|
|
21
|
+
return join(homedir(), ".config");
|
|
22
|
+
}
|
|
23
|
+
}
|
|
8
24
|
|
|
9
25
|
// todo (yoav): share type with cli
|
|
10
26
|
let localInfo: {
|
|
@@ -46,7 +62,8 @@ const Updater = {
|
|
|
46
62
|
|
|
47
63
|
const channelBucketUrl = await Updater.channelBucketUrl();
|
|
48
64
|
const cacheBuster = Math.random().toString(36).substring(7);
|
|
49
|
-
const
|
|
65
|
+
const platformFolder = `${localInfo.channel}-${currentOS}-${currentArch}`;
|
|
66
|
+
const updateInfoUrl = join(localInfo.bucketUrl, platformFolder, `update.json?${cacheBuster}`);
|
|
50
67
|
|
|
51
68
|
try {
|
|
52
69
|
const updateInfoResponse = await fetch(updateInfoUrl);
|
|
@@ -113,8 +130,9 @@ const Updater = {
|
|
|
113
130
|
}
|
|
114
131
|
|
|
115
132
|
// check if there's a patch file for it
|
|
133
|
+
const platformFolder = `${localInfo.channel}-${currentOS}-${currentArch}`;
|
|
116
134
|
const patchResponse = await fetch(
|
|
117
|
-
join(
|
|
135
|
+
join(localInfo.bucketUrl, platformFolder, `${currentHash}.patch`)
|
|
118
136
|
);
|
|
119
137
|
|
|
120
138
|
if (!patchResponse.ok) {
|
|
@@ -210,9 +228,21 @@ const Updater = {
|
|
|
210
228
|
// then just download it and unpack it
|
|
211
229
|
if (currentHash !== latestHash) {
|
|
212
230
|
const cacheBuster = Math.random().toString(36).substring(7);
|
|
231
|
+
const platformFolder = `${localInfo.channel}-${currentOS}-${currentArch}`;
|
|
232
|
+
// Platform-specific tarball naming
|
|
233
|
+
let tarballName: string;
|
|
234
|
+
if (currentOS === 'macos') {
|
|
235
|
+
tarballName = `${appFileName}.app.tar.zst`;
|
|
236
|
+
} else if (currentOS === 'win') {
|
|
237
|
+
tarballName = `${appFileName}.tar.zst`;
|
|
238
|
+
} else {
|
|
239
|
+
tarballName = `${appFileName}.tar.zst`;
|
|
240
|
+
}
|
|
241
|
+
|
|
213
242
|
const urlToLatestTarball = join(
|
|
214
|
-
|
|
215
|
-
|
|
243
|
+
localInfo.bucketUrl,
|
|
244
|
+
platformFolder,
|
|
245
|
+
tarballName
|
|
216
246
|
);
|
|
217
247
|
const prevVersionCompressedTarballPath = join(
|
|
218
248
|
appDataFolder,
|
|
@@ -289,16 +319,24 @@ const Updater = {
|
|
|
289
319
|
file: latestTarPath,
|
|
290
320
|
cwd: extractionFolder,
|
|
291
321
|
onentry: (entry) => {
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
appBundleSubpath
|
|
322
|
+
if (currentOS === 'macos') {
|
|
323
|
+
// find the first .app bundle in the tarball
|
|
324
|
+
// Some apps may have nested .app bundles
|
|
325
|
+
if (!appBundleSubpath && entry.path.endsWith(".app/")) {
|
|
326
|
+
appBundleSubpath = entry.path;
|
|
327
|
+
}
|
|
328
|
+
} else {
|
|
329
|
+
// For Windows/Linux, look for the main executable
|
|
330
|
+
// This assumes the tarball contains the app at the root
|
|
331
|
+
if (!appBundleSubpath) {
|
|
332
|
+
appBundleSubpath = "./";
|
|
333
|
+
}
|
|
296
334
|
}
|
|
297
335
|
},
|
|
298
336
|
});
|
|
299
337
|
|
|
300
338
|
if (!appBundleSubpath) {
|
|
301
|
-
console.error("Failed to find app
|
|
339
|
+
console.error("Failed to find app in tarball");
|
|
302
340
|
return;
|
|
303
341
|
}
|
|
304
342
|
|
|
@@ -306,14 +344,22 @@ const Updater = {
|
|
|
306
344
|
const newAppBundlePath = resolve(
|
|
307
345
|
join(extractionFolder, appBundleSubpath)
|
|
308
346
|
);
|
|
309
|
-
//
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
347
|
+
// Platform-specific app path calculation
|
|
348
|
+
let runningAppBundlePath: string;
|
|
349
|
+
if (currentOS === 'macos') {
|
|
350
|
+
// On macOS, executable is at Contents/MacOS/binary inside .app bundle
|
|
351
|
+
runningAppBundlePath = resolve(
|
|
352
|
+
dirname(process.execPath),
|
|
353
|
+
"..",
|
|
354
|
+
".."
|
|
355
|
+
);
|
|
356
|
+
} else {
|
|
357
|
+
// On Windows/Linux, the executable is the app itself
|
|
358
|
+
runningAppBundlePath = process.execPath;
|
|
359
|
+
}
|
|
360
|
+
// Platform-specific backup naming
|
|
361
|
+
const backupName = currentOS === 'macos' ? "backup.app" : "backup";
|
|
362
|
+
const backupAppBundlePath = join(extractionFolder, backupName);
|
|
317
363
|
|
|
318
364
|
try {
|
|
319
365
|
// const backupState = statSync(backupAppBundlePath);
|
|
@@ -329,7 +375,20 @@ const Updater = {
|
|
|
329
375
|
return;
|
|
330
376
|
}
|
|
331
377
|
|
|
332
|
-
|
|
378
|
+
// Cross-platform app launch
|
|
379
|
+
switch (currentOS) {
|
|
380
|
+
case 'macos':
|
|
381
|
+
await Bun.spawn(["open", runningAppBundlePath]);
|
|
382
|
+
break;
|
|
383
|
+
case 'win':
|
|
384
|
+
// On Windows, the runningAppBundlePath would be the .exe file
|
|
385
|
+
await Bun.spawn([runningAppBundlePath]);
|
|
386
|
+
break;
|
|
387
|
+
case 'linux':
|
|
388
|
+
// On Linux, directly execute the binary
|
|
389
|
+
await Bun.spawn([runningAppBundlePath]);
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
333
392
|
process.exit(0);
|
|
334
393
|
}
|
|
335
394
|
}
|
|
@@ -337,14 +396,14 @@ const Updater = {
|
|
|
337
396
|
|
|
338
397
|
channelBucketUrl: async () => {
|
|
339
398
|
await Updater.getLocallocalInfo();
|
|
340
|
-
|
|
341
|
-
return join(localInfo.bucketUrl,
|
|
399
|
+
const platformFolder = `${localInfo.channel}-${currentOS}-${currentArch}`;
|
|
400
|
+
return join(localInfo.bucketUrl, platformFolder);
|
|
342
401
|
},
|
|
343
402
|
|
|
344
403
|
appDataFolder: async () => {
|
|
345
404
|
await Updater.getLocallocalInfo();
|
|
346
405
|
const appDataFolder = join(
|
|
347
|
-
|
|
406
|
+
getAppDataDir(),
|
|
348
407
|
localInfo.identifier,
|
|
349
408
|
localInfo.name
|
|
350
409
|
);
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { platform, arch } from 'os';
|
|
2
|
+
|
|
3
|
+
export type SupportedOS = 'macos' | 'win' | 'linux';
|
|
4
|
+
export type SupportedArch = 'arm64' | 'x64';
|
|
5
|
+
|
|
6
|
+
// Cache platform() result to avoid multiple system calls
|
|
7
|
+
const platformName = platform();
|
|
8
|
+
const archName = arch();
|
|
9
|
+
|
|
10
|
+
// Determine OS once
|
|
11
|
+
export const OS: SupportedOS = (() => {
|
|
12
|
+
switch (platformName) {
|
|
13
|
+
case "win32":
|
|
14
|
+
return 'win';
|
|
15
|
+
case "darwin":
|
|
16
|
+
return 'macos';
|
|
17
|
+
case 'linux':
|
|
18
|
+
return 'linux';
|
|
19
|
+
default:
|
|
20
|
+
throw new Error(`Unsupported platform: ${platformName}`);
|
|
21
|
+
}
|
|
22
|
+
})();
|
|
23
|
+
|
|
24
|
+
// Determine ARCH once, with Windows override
|
|
25
|
+
export const ARCH: SupportedArch = (() => {
|
|
26
|
+
// Always use x64 for Windows since we only build x64 Windows binaries
|
|
27
|
+
if (OS === 'win') {
|
|
28
|
+
return 'x64';
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (archName) {
|
|
32
|
+
case "arm64":
|
|
33
|
+
return 'arm64';
|
|
34
|
+
case "x64":
|
|
35
|
+
return 'x64';
|
|
36
|
+
default:
|
|
37
|
+
throw new Error(`Unsupported architecture: ${archName}`);
|
|
38
|
+
}
|
|
39
|
+
})();
|
|
40
|
+
|
|
41
|
+
// Export functions for backwards compatibility if needed
|
|
42
|
+
export function getPlatformOS(): SupportedOS {
|
|
43
|
+
return OS;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function getPlatformArch(): SupportedArch {
|
|
47
|
+
return ARCH;
|
|
48
|
+
}
|
package/package.json
CHANGED
package/src/cli/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { join, dirname, basename } from "path";
|
|
|
2
2
|
import {
|
|
3
3
|
existsSync,
|
|
4
4
|
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
5
6
|
cpSync,
|
|
6
7
|
rmdirSync,
|
|
7
8
|
mkdirSync,
|
|
@@ -12,40 +13,12 @@ import {
|
|
|
12
13
|
import { execSync } from "child_process";
|
|
13
14
|
import tar from "tar";
|
|
14
15
|
import { ZstdInit } from "@oneidentity/zstd-js/wasm";
|
|
15
|
-
import {
|
|
16
|
+
import { OS, ARCH } from '../shared/platform';
|
|
17
|
+
import { getTemplate, getTemplateNames } from './templates/embedded';
|
|
16
18
|
// import { loadBsdiff, loadBspatch } from 'bsdiff-wasm';
|
|
17
19
|
// MacOS named pipes hang at around 4KB
|
|
18
20
|
const MAX_CHUNK_SIZE = 1024 * 2;
|
|
19
21
|
|
|
20
|
-
// TODO: dedup with built.ts
|
|
21
|
-
const OS: 'win' | 'linux' | 'macos' = getPlatform();
|
|
22
|
-
// Always use x64 for Windows since we only build x64 Windows binaries
|
|
23
|
-
const ARCH: 'arm64' | 'x64' = OS === 'win' ? 'x64' : getArch();
|
|
24
|
-
|
|
25
|
-
function getPlatform() {
|
|
26
|
-
switch (platform()) {
|
|
27
|
-
case "win32":
|
|
28
|
-
return 'win';
|
|
29
|
-
case "darwin":
|
|
30
|
-
return 'macos';
|
|
31
|
-
case 'linux':
|
|
32
|
-
return 'linux';
|
|
33
|
-
default:
|
|
34
|
-
throw 'unsupported platform';
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function getArch() {
|
|
39
|
-
switch (arch()) {
|
|
40
|
-
case "arm64":
|
|
41
|
-
return 'arm64';
|
|
42
|
-
case "x64":
|
|
43
|
-
return 'x64';
|
|
44
|
-
default:
|
|
45
|
-
throw 'unsupported arch'
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
22
|
|
|
50
23
|
const binExt = OS === 'win' ? '.exe' : '';
|
|
51
24
|
|
|
@@ -711,8 +684,57 @@ const bundleFileName = targetOS === 'macos' ? `${appFileName}.app` : appFileName
|
|
|
711
684
|
let proc = null;
|
|
712
685
|
|
|
713
686
|
if (commandArg === "init") {
|
|
714
|
-
|
|
715
|
-
|
|
687
|
+
const projectName = process.argv[indexOfElectrobun + 2] || "my-electrobun-app";
|
|
688
|
+
const templateName = process.argv.find(arg => arg.startsWith("--template="))?.split("=")[1] || "hello-world";
|
|
689
|
+
|
|
690
|
+
console.log(`🚀 Initializing Electrobun project: ${projectName}`);
|
|
691
|
+
|
|
692
|
+
// Validate template name
|
|
693
|
+
const availableTemplates = getTemplateNames();
|
|
694
|
+
if (!availableTemplates.includes(templateName)) {
|
|
695
|
+
console.error(`❌ Template "${templateName}" not found.`);
|
|
696
|
+
console.log(`Available templates: ${availableTemplates.join(", ")}`);
|
|
697
|
+
process.exit(1);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
const template = getTemplate(templateName);
|
|
701
|
+
if (!template) {
|
|
702
|
+
console.error(`❌ Could not load template "${templateName}"`);
|
|
703
|
+
process.exit(1);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Create project directory
|
|
707
|
+
const projectPath = join(process.cwd(), projectName);
|
|
708
|
+
if (existsSync(projectPath)) {
|
|
709
|
+
console.error(`❌ Directory "${projectName}" already exists.`);
|
|
710
|
+
process.exit(1);
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
mkdirSync(projectPath, { recursive: true });
|
|
714
|
+
|
|
715
|
+
// Extract template files
|
|
716
|
+
let fileCount = 0;
|
|
717
|
+
for (const [relativePath, content] of Object.entries(template.files)) {
|
|
718
|
+
const fullPath = join(projectPath, relativePath);
|
|
719
|
+
const dir = dirname(fullPath);
|
|
720
|
+
|
|
721
|
+
// Create directory if it doesn't exist
|
|
722
|
+
mkdirSync(dir, { recursive: true });
|
|
723
|
+
|
|
724
|
+
// Write file
|
|
725
|
+
writeFileSync(fullPath, content, 'utf-8');
|
|
726
|
+
fileCount++;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
console.log(`✅ Created ${fileCount} files from "${templateName}" template`);
|
|
730
|
+
console.log(`📁 Project created at: ${projectPath}`);
|
|
731
|
+
console.log("");
|
|
732
|
+
console.log("📦 Next steps:");
|
|
733
|
+
console.log(` cd ${projectName}`);
|
|
734
|
+
console.log(" bun install");
|
|
735
|
+
console.log(" bunx electrobun dev");
|
|
736
|
+
console.log("");
|
|
737
|
+
console.log("🎉 Happy building with Electrobun!");
|
|
716
738
|
} else if (commandArg === "build") {
|
|
717
739
|
// Ensure core binaries are available for the target platform before starting build
|
|
718
740
|
await ensureCoreDependencies(currentTarget.os, currentTarget.arch);
|
|
@@ -1306,7 +1328,7 @@ if (commandArg === "init") {
|
|
|
1306
1328
|
// 6.5. code sign and notarize the dmg
|
|
1307
1329
|
// 7. copy artifacts to directory [self-extractor dmg, zstd app bundle, bsdiff patch, update.json]
|
|
1308
1330
|
|
|
1309
|
-
//
|
|
1331
|
+
// Platform suffix is only used for folder names, not file names
|
|
1310
1332
|
const platformSuffix = `-${targetOS}-${targetARCH}`;
|
|
1311
1333
|
const tarPath = `${appBundleFolderPath}.tar`;
|
|
1312
1334
|
|
|
@@ -1331,8 +1353,7 @@ if (commandArg === "init") {
|
|
|
1331
1353
|
// than saving 1 more MB of space/bandwidth.
|
|
1332
1354
|
|
|
1333
1355
|
const compressedTarPath = `${tarPath}.zst`;
|
|
1334
|
-
|
|
1335
|
-
artifactsToUpload.push(platformCompressedTarPath);
|
|
1356
|
+
artifactsToUpload.push(compressedTarPath);
|
|
1336
1357
|
|
|
1337
1358
|
// zstd compress tarball
|
|
1338
1359
|
// todo (yoav): consider using c bindings for zstd for speed instead of wasm
|
|
@@ -1361,8 +1382,6 @@ if (commandArg === "init") {
|
|
|
1361
1382
|
);
|
|
1362
1383
|
|
|
1363
1384
|
await Bun.write(compressedTarPath, compressedData);
|
|
1364
|
-
// Copy to platform-specific filename for upload
|
|
1365
|
-
cpSync(compressedTarPath, platformCompressedTarPath);
|
|
1366
1385
|
}
|
|
1367
1386
|
});
|
|
1368
1387
|
|
|
@@ -1416,8 +1435,7 @@ if (commandArg === "init") {
|
|
|
1416
1435
|
console.log("creating dmg...");
|
|
1417
1436
|
// make a dmg
|
|
1418
1437
|
const dmgPath = join(buildFolder, `${appFileName}.dmg`);
|
|
1419
|
-
|
|
1420
|
-
artifactsToUpload.push(platformDmgPath);
|
|
1438
|
+
artifactsToUpload.push(dmgPath);
|
|
1421
1439
|
// hdiutil create -volname "YourAppName" -srcfolder /path/to/YourApp.app -ov -format UDZO YourAppName.dmg
|
|
1422
1440
|
// Note: use ULFO (lzfse) for better compatibility with large CEF frameworks and modern macOS
|
|
1423
1441
|
execSync(
|
|
@@ -1437,9 +1455,6 @@ if (commandArg === "init") {
|
|
|
1437
1455
|
} else {
|
|
1438
1456
|
console.log("skipping notarization");
|
|
1439
1457
|
}
|
|
1440
|
-
|
|
1441
|
-
// Copy to platform-specific filename
|
|
1442
|
-
cpSync(dmgPath, platformDmgPath);
|
|
1443
1458
|
} else {
|
|
1444
1459
|
// For Windows and Linux, add the self-extracting bundle directly
|
|
1445
1460
|
const platformBundlePath = join(buildFolder, `${appFileName}${platformSuffix}${targetOS === 'win' ? '.exe' : ''}`);
|
|
@@ -1447,10 +1462,10 @@ if (commandArg === "init") {
|
|
|
1447
1462
|
if (targetOS === 'win') {
|
|
1448
1463
|
// On Windows, create a self-extracting exe
|
|
1449
1464
|
// For now, just copy the bundle folder
|
|
1450
|
-
artifactsToUpload.push(compressedTarPath
|
|
1465
|
+
artifactsToUpload.push(compressedTarPath);
|
|
1451
1466
|
} else if (targetOS === 'linux') {
|
|
1452
1467
|
// On Linux, create a tar.gz of the bundle
|
|
1453
|
-
const linuxTarPath = join(buildFolder, `${appFileName}
|
|
1468
|
+
const linuxTarPath = join(buildFolder, `${appFileName}.tar.gz`);
|
|
1454
1469
|
execSync(`tar -czf ${escapePathForTerminal(linuxTarPath)} -C ${escapePathForTerminal(buildFolder)} ${escapePathForTerminal(basename(appBundleFolderPath))}`);
|
|
1455
1470
|
artifactsToUpload.push(linuxTarPath);
|
|
1456
1471
|
}
|
|
@@ -1478,9 +1493,8 @@ if (commandArg === "init") {
|
|
|
1478
1493
|
// bucketUrl: config.release.bucketUrl
|
|
1479
1494
|
});
|
|
1480
1495
|
|
|
1481
|
-
//
|
|
1482
|
-
|
|
1483
|
-
await Bun.write(join(artifactFolder, platformUpdateJsonName), updateJsonContent);
|
|
1496
|
+
// update.json (no platform suffix in filename, platform is in folder name)
|
|
1497
|
+
await Bun.write(join(artifactFolder, 'update.json'), updateJsonContent);
|
|
1484
1498
|
|
|
1485
1499
|
// generate bsdiff
|
|
1486
1500
|
// https://storage.googleapis.com/eggbun-static/electrobun-playground/canary/ElectrobunPlayground-canary.app.tar.zst
|
|
@@ -1495,8 +1509,8 @@ if (commandArg === "init") {
|
|
|
1495
1509
|
} else {
|
|
1496
1510
|
const urlToPrevUpdateJson = join(
|
|
1497
1511
|
config.release.bucketUrl,
|
|
1498
|
-
|
|
1499
|
-
|
|
1512
|
+
buildSubFolder,
|
|
1513
|
+
'update.json'
|
|
1500
1514
|
);
|
|
1501
1515
|
const cacheBuster = Math.random().toString(36).substring(7);
|
|
1502
1516
|
const updateJsonResponse = await fetch(
|
|
@@ -1507,8 +1521,8 @@ if (commandArg === "init") {
|
|
|
1507
1521
|
|
|
1508
1522
|
const urlToLatestTarball = join(
|
|
1509
1523
|
config.release.bucketUrl,
|
|
1510
|
-
|
|
1511
|
-
`${appFileName}.app
|
|
1524
|
+
buildSubFolder,
|
|
1525
|
+
`${appFileName}.app.tar.zst`
|
|
1512
1526
|
);
|
|
1513
1527
|
|
|
1514
1528
|
|
|
@@ -1555,8 +1569,7 @@ if (commandArg === "init") {
|
|
|
1555
1569
|
// especially for creating multiple diffs in parallel
|
|
1556
1570
|
const bsdiffpath = targetPaths.BSDIFF;
|
|
1557
1571
|
const patchFilePath = join(buildFolder, `${prevHash}.patch`);
|
|
1558
|
-
|
|
1559
|
-
artifactsToUpload.push(platformPatchFilePath);
|
|
1572
|
+
artifactsToUpload.push(patchFilePath);
|
|
1560
1573
|
const result = Bun.spawnSync(
|
|
1561
1574
|
[bsdiffpath, prevTarballPath, tarPath, patchFilePath, "--use-zstd"],
|
|
1562
1575
|
{ cwd: buildFolder }
|
|
@@ -1566,8 +1579,6 @@ if (commandArg === "init") {
|
|
|
1566
1579
|
result.stdout.toString(),
|
|
1567
1580
|
result.stderr.toString()
|
|
1568
1581
|
);
|
|
1569
|
-
// Copy to platform-specific filename
|
|
1570
|
-
cpSync(patchFilePath, platformPatchFilePath);
|
|
1571
1582
|
}
|
|
1572
1583
|
} else {
|
|
1573
1584
|
console.log("prevoius version not found at: ", urlToLatestTarball);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# Electrobun Hello World
|
|
2
|
+
|
|
3
|
+
A simple Electrobun app to get you started with the framework.
|
|
4
|
+
|
|
5
|
+
## What You'll See
|
|
6
|
+
|
|
7
|
+
This hello world app demonstrates:
|
|
8
|
+
- **Native Window**: A cross-platform desktop window
|
|
9
|
+
- **Web-based UI**: Modern HTML, CSS, and JavaScript interface
|
|
10
|
+
- **Simple Architecture**: Clean separation between Bun process and UI
|
|
11
|
+
|
|
12
|
+
## Getting Started
|
|
13
|
+
|
|
14
|
+
1. Install dependencies:
|
|
15
|
+
```bash
|
|
16
|
+
bun install
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
2. Run in development mode:
|
|
20
|
+
```bash
|
|
21
|
+
bun run dev
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
3. Build for production:
|
|
25
|
+
```bash
|
|
26
|
+
bun run build
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Project Structure
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
src/
|
|
33
|
+
├── bun/
|
|
34
|
+
│ └── index.ts # Main process - creates and manages windows
|
|
35
|
+
└── mainview/
|
|
36
|
+
├── index.html # Your app's UI
|
|
37
|
+
├── index.css # Styles
|
|
38
|
+
└── index.ts # View logic
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Next Steps
|
|
42
|
+
|
|
43
|
+
Ready to build something more complex? Check out:
|
|
44
|
+
|
|
45
|
+
- **[Documentation](https://docs.electrobun.dev)** - Learn about all Electrobun features
|
|
46
|
+
- **[Examples](https://github.com/blackboardsh/electrobun/tree/main/playground)** - See advanced features like RPC, menus, and system tray
|
|
47
|
+
- **[GitHub](https://github.com/blackboardsh/electrobun)** - Star the repo and join the community
|
|
48
|
+
|
|
49
|
+
### Add More Features
|
|
50
|
+
|
|
51
|
+
Want to extend this app? Try adding:
|
|
52
|
+
- RPC communication between Bun and webview
|
|
53
|
+
- Native menus and system tray
|
|
54
|
+
- File dialogs and system integration
|
|
55
|
+
- Multiple windows and views
|
|
56
|
+
|
|
57
|
+
Happy building! 🚀
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "electrobun-hello-world",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"electrobun": "latest",
|
|
8
|
+
},
|
|
9
|
+
"devDependencies": {
|
|
10
|
+
"@types/bun": "latest",
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
},
|
|
14
|
+
"packages": {
|
|
15
|
+
"@oneidentity/zstd-js": ["@oneidentity/zstd-js@1.0.3", "", { "dependencies": { "@types/emscripten": "^1.39.4" } }, "sha512-Jm6sawqxLzBrjC4sg2BeXToa33yPzUmq20CKsehKY2++D/gHb/oSwVjNgT+RH4vys+r8FynrgcNzGwhZWMLzfQ=="],
|
|
16
|
+
|
|
17
|
+
"@types/bun": ["@types/bun@1.2.19", "", { "dependencies": { "bun-types": "1.2.19" } }, "sha512-d9ZCmrH3CJ2uYKXQIUuZ/pUnTqIvLDS0SK7pFmbx8ma+ziH/FRMoAq5bYpRG7y+w1gl+HgyNZbtqgMq4W4e2Lg=="],
|
|
18
|
+
|
|
19
|
+
"@types/emscripten": ["@types/emscripten@1.40.1", "", {}, "sha512-sr53lnYkQNhjHNN0oJDdUm5564biioI5DuOpycufDVK7D3y+GR3oUswe2rlwY1nPNyusHbrJ9WoTyIHl4/Bpwg=="],
|
|
20
|
+
|
|
21
|
+
"@types/filesystem": ["@types/filesystem@0.0.36", "", { "dependencies": { "@types/filewriter": "*" } }, "sha512-vPDXOZuannb9FZdxgHnqSwAG/jvdGM8Wq+6N4D/d80z+D4HWH+bItqsZaVRQykAn6WEVeEkLm2oQigyHtgb0RA=="],
|
|
22
|
+
|
|
23
|
+
"@types/filewriter": ["@types/filewriter@0.0.33", "", {}, "sha512-xFU8ZXTw4gd358lb2jw25nxY9QAgqn2+bKKjKOYfNCzN4DKCFetK7sPtrlpg66Ywe3vWY9FNxprZawAh9wfJ3g=="],
|
|
24
|
+
|
|
25
|
+
"@types/har-format": ["@types/har-format@1.2.16", "", {}, "sha512-fluxdy7ryD3MV6h8pTfTYpy/xQzCFC7m89nOH9y94cNqJ1mDIDPut7MnRHI3F6qRmh/cT2fUjG1MLdCNb4hE9A=="],
|
|
26
|
+
|
|
27
|
+
"@types/node": ["@types/node@24.1.0", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w=="],
|
|
28
|
+
|
|
29
|
+
"@types/react": ["@types/react@19.1.9", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA=="],
|
|
30
|
+
|
|
31
|
+
"@types/webextension-polyfill": ["@types/webextension-polyfill@0.12.3", "", {}, "sha512-F58aDVSeN/MjUGazXo/cPsmR76EvqQhQ1v4x23hFjUX0cfAJYE+JBWwiOGW36/VJGGxoH74sVlRIF3z7SJCKyg=="],
|
|
32
|
+
|
|
33
|
+
"browser-namespace": ["browser-namespace@1.4.0", "", { "dependencies": { "@types/filesystem": "*", "@types/har-format": "*", "@types/webextension-polyfill": "*" } }, "sha512-9b4yNTNs+8HVPssSq8RSZMRunf+G4cVQ2PMtOTn+uEVFOW5C0Uo+eGXuJ5LfxS1UDph5oAdWj92thPyxVhpqXg=="],
|
|
34
|
+
|
|
35
|
+
"bun-types": ["bun-types@1.2.19", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-uAOTaZSPuYsWIXRpj7o56Let0g/wjihKCkeRqUBhlLVM/Bt+Fj9xTo+LhC1OV1XDaGkz4hNC80et5xgy+9KTHQ=="],
|
|
36
|
+
|
|
37
|
+
"chownr": ["chownr@2.0.0", "", {}, "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ=="],
|
|
38
|
+
|
|
39
|
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
|
40
|
+
|
|
41
|
+
"electrobun": ["electrobun@0.0.18", "", { "dependencies": { "@oneidentity/zstd-js": "^1.0.3", "rpc-anywhere": "1.5.0", "tar": "^6.2.1" }, "bin": { "electrobun": "dist/electrobun" } }, "sha512-RyMNGcAaHklicZlJToGfN3fVZGKHpxZv6o8S96TK9tHSY/SRze5bNPIGUnY9wr/BbWuQW5gGUGaVIWWqa5NSZQ=="],
|
|
42
|
+
|
|
43
|
+
"fs-minipass": ["fs-minipass@2.1.0", "", { "dependencies": { "minipass": "^3.0.0" } }, "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg=="],
|
|
44
|
+
|
|
45
|
+
"minipass": ["minipass@5.0.0", "", {}, "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ=="],
|
|
46
|
+
|
|
47
|
+
"minizlib": ["minizlib@2.1.2", "", { "dependencies": { "minipass": "^3.0.0", "yallist": "^4.0.0" } }, "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg=="],
|
|
48
|
+
|
|
49
|
+
"mkdirp": ["mkdirp@1.0.4", "", { "bin": { "mkdirp": "bin/cmd.js" } }, "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="],
|
|
50
|
+
|
|
51
|
+
"rpc-anywhere": ["rpc-anywhere@1.5.0", "", { "dependencies": { "browser-namespace": "^1.4.0" } }, "sha512-ZYrB0foAM4oE7oBnUH3BL7LwtW9d6+RkzL/rFnjj8GCaFt5c81Rbw6oVl6u9AMsGONsKeJX0mL62TpbPXSO6og=="],
|
|
52
|
+
|
|
53
|
+
"tar": ["tar@6.2.1", "", { "dependencies": { "chownr": "^2.0.0", "fs-minipass": "^2.0.0", "minipass": "^5.0.0", "minizlib": "^2.1.1", "mkdirp": "^1.0.3", "yallist": "^4.0.0" } }, "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A=="],
|
|
54
|
+
|
|
55
|
+
"undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="],
|
|
56
|
+
|
|
57
|
+
"yallist": ["yallist@4.0.0", "", {}, "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="],
|
|
58
|
+
|
|
59
|
+
"fs-minipass/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
|
60
|
+
|
|
61
|
+
"minizlib/minipass": ["minipass@3.3.6", "", { "dependencies": { "yallist": "^4.0.0" } }, "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw=="],
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "electrobun-hello-world",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A simple Electrobun app showcasing core features",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "electrobun dev",
|
|
7
|
+
"build": "electrobun build",
|
|
8
|
+
"start": "bun run build && bun run dev"
|
|
9
|
+
},
|
|
10
|
+
"dependencies": {
|
|
11
|
+
"electrobun": "latest"
|
|
12
|
+
},
|
|
13
|
+
"devDependencies": {
|
|
14
|
+
"@types/bun": "latest"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { BrowserWindow } from "electrobun/bun";
|
|
2
|
+
|
|
3
|
+
// Create the main application window
|
|
4
|
+
const mainWindow = new BrowserWindow({
|
|
5
|
+
title: "Hello Electrobun!",
|
|
6
|
+
url: "views://main/index.html",
|
|
7
|
+
frame: {
|
|
8
|
+
width: 800,
|
|
9
|
+
height: 600,
|
|
10
|
+
x: 200,
|
|
11
|
+
y: 200,
|
|
12
|
+
},
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
console.log("Hello Electrobun app started!");
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
* {
|
|
2
|
+
box-sizing: border-box;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
body {
|
|
6
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
|
|
7
|
+
margin: 0;
|
|
8
|
+
padding: 0;
|
|
9
|
+
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
|
10
|
+
color: #333;
|
|
11
|
+
min-height: 100vh;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.container {
|
|
15
|
+
max-width: 800px;
|
|
16
|
+
margin: 0 auto;
|
|
17
|
+
padding: 40px 20px;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
h1 {
|
|
21
|
+
color: white;
|
|
22
|
+
font-size: 3rem;
|
|
23
|
+
text-align: center;
|
|
24
|
+
margin-bottom: 8px;
|
|
25
|
+
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.subtitle {
|
|
29
|
+
color: rgba(255, 255, 255, 0.9);
|
|
30
|
+
font-size: 1.25rem;
|
|
31
|
+
text-align: center;
|
|
32
|
+
margin-top: 0;
|
|
33
|
+
margin-bottom: 40px;
|
|
34
|
+
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
.welcome-section {
|
|
38
|
+
background: white;
|
|
39
|
+
border-radius: 12px;
|
|
40
|
+
padding: 30px;
|
|
41
|
+
margin: 30px 0;
|
|
42
|
+
box-shadow: 0 8px 25px rgba(0, 0, 0, 0.15);
|
|
43
|
+
line-height: 1.6;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
h2 {
|
|
47
|
+
color: #2563eb;
|
|
48
|
+
margin-top: 30px;
|
|
49
|
+
margin-bottom: 15px;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
ul {
|
|
53
|
+
margin: 20px 0;
|
|
54
|
+
padding-left: 20px;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
li {
|
|
58
|
+
margin: 8px 0;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.links {
|
|
62
|
+
display: flex;
|
|
63
|
+
gap: 15px;
|
|
64
|
+
margin: 25px 0;
|
|
65
|
+
flex-wrap: wrap;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.doc-link {
|
|
69
|
+
display: inline-block;
|
|
70
|
+
background: #2563eb;
|
|
71
|
+
color: white;
|
|
72
|
+
text-decoration: none;
|
|
73
|
+
padding: 12px 20px;
|
|
74
|
+
border-radius: 8px;
|
|
75
|
+
font-weight: 500;
|
|
76
|
+
transition: all 0.2s ease;
|
|
77
|
+
box-shadow: 0 2px 4px rgba(37, 99, 235, 0.2);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.doc-link:hover {
|
|
81
|
+
background: #1d4ed8;
|
|
82
|
+
transform: translateY(-1px);
|
|
83
|
+
box-shadow: 0 4px 8px rgba(37, 99, 235, 0.3);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
code {
|
|
87
|
+
background: #f1f5f9;
|
|
88
|
+
color: #475569;
|
|
89
|
+
padding: 2px 6px;
|
|
90
|
+
border-radius: 4px;
|
|
91
|
+
font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
|
|
92
|
+
font-size: 0.9em;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.footer {
|
|
96
|
+
text-align: center;
|
|
97
|
+
color: rgba(255, 255, 255, 0.8);
|
|
98
|
+
margin-top: 40px;
|
|
99
|
+
padding: 20px;
|
|
100
|
+
background: rgba(255, 255, 255, 0.1);
|
|
101
|
+
border-radius: 8px;
|
|
102
|
+
backdrop-filter: blur(10px);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.footer p {
|
|
106
|
+
margin: 8px 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* Dark mode support */
|
|
110
|
+
@media (prefers-color-scheme: dark) {
|
|
111
|
+
.welcome-section {
|
|
112
|
+
background: #1f2937;
|
|
113
|
+
color: #f3f4f6;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
h2 {
|
|
117
|
+
color: #60a5fa;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
code {
|
|
121
|
+
background: #374151;
|
|
122
|
+
color: #d1d5db;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>Hello Electrobun!</title>
|
|
7
|
+
<link rel="stylesheet" href="index.css">
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div class="container">
|
|
11
|
+
<h1>Hello Electrobun! 🎉</h1>
|
|
12
|
+
<p class="subtitle">A fast, cross-platform desktop app framework</p>
|
|
13
|
+
|
|
14
|
+
<div class="welcome-section">
|
|
15
|
+
<p>Welcome to your first Electrobun app! This framework combines the power of Bun with native desktop capabilities.</p>
|
|
16
|
+
|
|
17
|
+
<h2>What is Electrobun?</h2>
|
|
18
|
+
<ul>
|
|
19
|
+
<li><strong>Fast:</strong> Built on Bun's lightning-fast JavaScript runtime</li>
|
|
20
|
+
<li><strong>Native:</strong> Access to system APIs like menus, trays, and file dialogs</li>
|
|
21
|
+
<li><strong>Cross-platform:</strong> Works on macOS, Windows, and Linux</li>
|
|
22
|
+
<li><strong>Web-based UI:</strong> Use familiar HTML, CSS, and JavaScript for your interface</li>
|
|
23
|
+
</ul>
|
|
24
|
+
|
|
25
|
+
<h2>Get Started</h2>
|
|
26
|
+
<p>Ready to build something amazing? Check out the documentation and examples:</p>
|
|
27
|
+
|
|
28
|
+
<div class="links">
|
|
29
|
+
<a href="https://docs.electrobun.dev" target="_blank" class="doc-link">
|
|
30
|
+
📚 Documentation
|
|
31
|
+
</a>
|
|
32
|
+
<a href="https://github.com/blackboardsh/electrobun" target="_blank" class="doc-link">
|
|
33
|
+
🐙 GitHub Repository
|
|
34
|
+
</a>
|
|
35
|
+
<a href="https://docs.electrobun.dev/examples" target="_blank" class="doc-link">
|
|
36
|
+
💡 Examples
|
|
37
|
+
</a>
|
|
38
|
+
</div>
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<div class="footer">
|
|
42
|
+
<p>Edit <code>src/bun/index.ts</code> and <code>src/mainview/</code> to customize your app</p>
|
|
43
|
+
<p>Press F12 to open DevTools</p>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
</body>
|
|
47
|
+
</html>
|