electrobun 0.0.19-beta.99 → 0.1.1
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 +1 -1
- package/dist/api/browser/webviewtag.ts +54 -2
- package/dist/api/bun/ElectrobunConfig.ts +171 -0
- package/dist/api/bun/core/BrowserWindow.ts +4 -0
- package/dist/api/bun/core/Tray.ts +14 -0
- package/dist/api/bun/core/Updater.ts +4 -3
- package/dist/api/bun/index.ts +2 -0
- package/dist/api/bun/proc/native.ts +107 -5
- package/dist/main.js +5 -4
- package/package.json +4 -2
- package/src/cli/index.ts +621 -151
- package/templates/hello-world/bun.lock +164 -2
- package/templates/hello-world/electrobun.config.ts +28 -0
- package/templates/hello-world/src/bun/index.ts +2 -2
- package/templates/hello-world/src/mainview/index.html +5 -6
- package/templates/hello-world/src/mainview/index.ts +1 -5
- package/templates/interactive-playground/README.md +26 -0
- package/templates/interactive-playground/assets/tray-icon.png +0 -0
- package/templates/interactive-playground/electrobun.config.ts +36 -0
- package/templates/interactive-playground/package-lock.json +36 -0
- package/templates/interactive-playground/package.json +15 -0
- package/templates/interactive-playground/src/bun/demos/files.ts +70 -0
- package/templates/interactive-playground/src/bun/demos/menus.ts +139 -0
- package/templates/interactive-playground/src/bun/demos/rpc.ts +83 -0
- package/templates/interactive-playground/src/bun/demos/system.ts +72 -0
- package/templates/interactive-playground/src/bun/demos/updates.ts +105 -0
- package/templates/interactive-playground/src/bun/demos/windows.ts +90 -0
- package/templates/interactive-playground/src/bun/index.ts +124 -0
- package/templates/interactive-playground/src/bun/types/rpc.ts +109 -0
- package/templates/interactive-playground/src/mainview/components/EventLog.ts +107 -0
- package/templates/interactive-playground/src/mainview/components/Sidebar.ts +65 -0
- package/templates/interactive-playground/src/mainview/components/Toast.ts +57 -0
- package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +211 -0
- package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +102 -0
- package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +229 -0
- package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +132 -0
- package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +411 -0
- package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +207 -0
- package/templates/interactive-playground/src/mainview/index.css +538 -0
- package/templates/interactive-playground/src/mainview/index.html +103 -0
- package/templates/interactive-playground/src/mainview/index.ts +238 -0
- package/templates/multitab-browser/README.md +34 -0
- package/templates/multitab-browser/bun.lock +224 -0
- package/templates/multitab-browser/electrobun.config.ts +32 -0
- package/templates/multitab-browser/package-lock.json +20 -0
- package/templates/multitab-browser/package.json +12 -0
- package/templates/multitab-browser/src/bun/index.ts +144 -0
- package/templates/multitab-browser/src/bun/tabManager.ts +200 -0
- package/templates/multitab-browser/src/bun/types/rpc.ts +78 -0
- package/templates/multitab-browser/src/mainview/index.css +487 -0
- package/templates/multitab-browser/src/mainview/index.html +94 -0
- package/templates/multitab-browser/src/mainview/index.ts +634 -0
- package/templates/photo-booth/README.md +108 -0
- package/templates/photo-booth/bun.lock +239 -0
- package/templates/photo-booth/electrobun.config.ts +32 -0
- package/templates/photo-booth/package.json +17 -0
- package/templates/photo-booth/src/bun/index.ts +92 -0
- package/templates/photo-booth/src/mainview/index.css +465 -0
- package/templates/photo-booth/src/mainview/index.html +124 -0
- package/templates/photo-booth/src/mainview/index.ts +499 -0
- package/tests/bun.lock +14 -0
- package/tests/electrobun.config.ts +45 -0
- package/tests/package-lock.json +36 -0
- package/tests/package.json +13 -0
- package/tests/src/bun/index.ts +100 -0
- package/tests/src/bun/test-runner.ts +508 -0
- package/tests/src/mainview/index.html +110 -0
- package/tests/src/mainview/index.ts +458 -0
- package/tests/src/mainview/styles/main.css +451 -0
- package/tests/src/testviews/tray-test.html +57 -0
- package/tests/src/testviews/webview-mask.html +114 -0
- package/tests/src/testviews/webview-navigation.html +36 -0
- package/tests/src/testviews/window-create.html +17 -0
- package/tests/src/testviews/window-events.html +29 -0
- package/tests/src/testviews/window-focus.html +37 -0
- package/tests/src/webviewtag/index.ts +11 -0
- package/templates/hello-world/electrobun.config +0 -18
package/README.md
CHANGED
|
@@ -20,7 +20,7 @@ Visit <a href="https://www.electrobun.dev/">Electrobun.dev</a> to see api docume
|
|
|
20
20
|
- Write typescript for the main process and webviews without having to think about it.
|
|
21
21
|
- Isolation between main and webview processes with fast, typed, easy to implement RPC between them.
|
|
22
22
|
- Small self-extracting app bundles ~12MB (when using system webview, most of this is the bun runtime)
|
|
23
|
-
- Even smaller app updates as small as
|
|
23
|
+
- Even smaller app updates as small as 14KB (using bsdiff it only downloads tiny patches between versions)
|
|
24
24
|
- Provide everything you need in one tightly integrated workflow to start writing code in 5 minutes and distribute in 10.
|
|
25
25
|
|
|
26
26
|
## Architecture
|
|
@@ -54,6 +54,7 @@ const ConfigureWebviewTags = (
|
|
|
54
54
|
hiddenMirrorMode: boolean = false;
|
|
55
55
|
wasZeroRect: boolean = false;
|
|
56
56
|
isMirroring: boolean = false;
|
|
57
|
+
masks: string = '';
|
|
57
58
|
|
|
58
59
|
partition: string | null = null;
|
|
59
60
|
|
|
@@ -83,7 +84,15 @@ const ConfigureWebviewTags = (
|
|
|
83
84
|
this.lastRect = rect;
|
|
84
85
|
|
|
85
86
|
const url = this.src || this.getAttribute("src");
|
|
86
|
-
const html = this.html || this.getAttribute("html");
|
|
87
|
+
const html = this.html || this.getAttribute("html");
|
|
88
|
+
|
|
89
|
+
const maskSelectors = this.masks || this.getAttribute("masks");
|
|
90
|
+
|
|
91
|
+
if (maskSelectors) {
|
|
92
|
+
maskSelectors.split(',').forEach(s => {
|
|
93
|
+
this.maskSelectors.add(s);
|
|
94
|
+
})
|
|
95
|
+
}
|
|
87
96
|
|
|
88
97
|
const webviewId = await this.internalRpc.request.webviewTagInit({
|
|
89
98
|
hostWebviewId: window.__electrobunWebviewId,
|
|
@@ -371,7 +380,12 @@ const ConfigureWebviewTags = (
|
|
|
371
380
|
// this.mutationObserver?.disconnect();
|
|
372
381
|
window.removeEventListener("resize", this.boundForceSyncDimensions);
|
|
373
382
|
window.removeEventListener("scroll", this.boundSyncDimensions);
|
|
374
|
-
|
|
383
|
+
|
|
384
|
+
if (this.webviewId) {
|
|
385
|
+
this.internalRpc.send.webviewTagRemove({ id: this.webviewId });
|
|
386
|
+
// Mark webview as removed to prevent further method calls
|
|
387
|
+
this.webviewId = undefined;
|
|
388
|
+
}
|
|
375
389
|
}
|
|
376
390
|
|
|
377
391
|
static get observedAttributes() {
|
|
@@ -393,6 +407,7 @@ const ConfigureWebviewTags = (
|
|
|
393
407
|
|
|
394
408
|
updateIFrameSrc(src: string) {
|
|
395
409
|
if (!this.webviewId) {
|
|
410
|
+
console.warn('updateIFrameSrc called on removed webview');
|
|
396
411
|
return;
|
|
397
412
|
}
|
|
398
413
|
this.internalRpc.send.webviewTagUpdateSrc({
|
|
@@ -403,6 +418,7 @@ const ConfigureWebviewTags = (
|
|
|
403
418
|
|
|
404
419
|
updateIFrameHtml(html: string) {
|
|
405
420
|
if (!this.webviewId) {
|
|
421
|
+
console.warn('updateIFrameHtml called on removed webview');
|
|
406
422
|
return;
|
|
407
423
|
}
|
|
408
424
|
|
|
@@ -414,6 +430,7 @@ const ConfigureWebviewTags = (
|
|
|
414
430
|
|
|
415
431
|
updateIFramePreload(preload: string) {
|
|
416
432
|
if (!this.webviewId) {
|
|
433
|
+
console.warn('updateIFramePreload called on removed webview');
|
|
417
434
|
return;
|
|
418
435
|
}
|
|
419
436
|
this.internalRpc.send.webviewTagUpdatePreload({
|
|
@@ -423,17 +440,33 @@ const ConfigureWebviewTags = (
|
|
|
423
440
|
}
|
|
424
441
|
|
|
425
442
|
goBack() {
|
|
443
|
+
if (!this.webviewId) {
|
|
444
|
+
console.warn('goBack called on removed webview');
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
426
447
|
this.internalRpc.send.webviewTagGoBack({ id: this.webviewId });
|
|
427
448
|
}
|
|
428
449
|
|
|
429
450
|
goForward() {
|
|
451
|
+
if (!this.webviewId) {
|
|
452
|
+
console.warn('goForward called on removed webview');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
430
455
|
this.internalRpc.send.webviewTagGoForward({ id: this.webviewId });
|
|
431
456
|
}
|
|
432
457
|
|
|
433
458
|
reload() {
|
|
459
|
+
if (!this.webviewId) {
|
|
460
|
+
console.warn('reload called on removed webview');
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
434
463
|
this.internalRpc.send.webviewTagReload({ id: this.webviewId });
|
|
435
464
|
}
|
|
436
465
|
loadURL(url: string) {
|
|
466
|
+
if (!this.webviewId) {
|
|
467
|
+
console.warn('loadURL called on removed webview');
|
|
468
|
+
return;
|
|
469
|
+
}
|
|
437
470
|
this.setAttribute("src", url);
|
|
438
471
|
this.internalRpc.send.webviewTagUpdateSrc({
|
|
439
472
|
id: this.webviewId,
|
|
@@ -441,6 +474,10 @@ const ConfigureWebviewTags = (
|
|
|
441
474
|
});
|
|
442
475
|
}
|
|
443
476
|
loadHTML(html: string) {
|
|
477
|
+
if (!this.webviewId) {
|
|
478
|
+
console.warn('loadHTML called on removed webview');
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
444
481
|
this.setAttribute("html", html);
|
|
445
482
|
this.internalRpc.send.webviewTagUpdateHtml({
|
|
446
483
|
id: this.webviewId,
|
|
@@ -450,6 +487,11 @@ const ConfigureWebviewTags = (
|
|
|
450
487
|
|
|
451
488
|
// This sets the native webview hovering over the dom to be transparent
|
|
452
489
|
toggleTransparent(transparent?: boolean, bypassState?: boolean) {
|
|
490
|
+
if (!this.webviewId) {
|
|
491
|
+
console.warn('toggleTransparent called on removed webview');
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
|
|
453
495
|
if (!bypassState) {
|
|
454
496
|
if (typeof transparent === "undefined") {
|
|
455
497
|
this.transparent = !this.transparent;
|
|
@@ -464,6 +506,11 @@ const ConfigureWebviewTags = (
|
|
|
464
506
|
});
|
|
465
507
|
}
|
|
466
508
|
togglePassthrough(enablePassthrough?: boolean, bypassState?: boolean) {
|
|
509
|
+
if (!this.webviewId) {
|
|
510
|
+
console.warn('togglePassthrough called on removed webview');
|
|
511
|
+
return;
|
|
512
|
+
}
|
|
513
|
+
|
|
467
514
|
if (!bypassState) {
|
|
468
515
|
if (typeof enablePassthrough === "undefined") {
|
|
469
516
|
this.passthroughEnabled = !this.passthroughEnabled;
|
|
@@ -480,6 +527,11 @@ const ConfigureWebviewTags = (
|
|
|
480
527
|
}
|
|
481
528
|
|
|
482
529
|
toggleHidden(hidden?: boolean, bypassState?: boolean) {
|
|
530
|
+
if (!this.webviewId) {
|
|
531
|
+
console.warn('toggleHidden called on removed webview');
|
|
532
|
+
return;
|
|
533
|
+
}
|
|
534
|
+
|
|
483
535
|
if (!bypassState) {
|
|
484
536
|
if (typeof hidden === "undefined") {
|
|
485
537
|
this.hidden = !this.hidden;
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Electrobun configuration type definitions
|
|
3
|
+
* Used in electrobun.config.ts files
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface ElectrobunConfig {
|
|
7
|
+
/**
|
|
8
|
+
* Application metadata configuration
|
|
9
|
+
*/
|
|
10
|
+
app: {
|
|
11
|
+
/**
|
|
12
|
+
* The display name of your application
|
|
13
|
+
*/
|
|
14
|
+
name: string;
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Unique identifier for your application (e.g., "com.example.myapp")
|
|
18
|
+
* Used for platform-specific identifiers
|
|
19
|
+
*/
|
|
20
|
+
identifier: string;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Application version string (e.g., "1.0.0")
|
|
24
|
+
*/
|
|
25
|
+
version: string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Build configuration options
|
|
30
|
+
*/
|
|
31
|
+
build?: {
|
|
32
|
+
/**
|
|
33
|
+
* Bun process build configuration
|
|
34
|
+
*/
|
|
35
|
+
bun?: {
|
|
36
|
+
/**
|
|
37
|
+
* Entry point for the main Bun process
|
|
38
|
+
* @default "src/bun/index.ts"
|
|
39
|
+
*/
|
|
40
|
+
entrypoint?: string;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* External modules to exclude from bundling
|
|
44
|
+
* @default []
|
|
45
|
+
*/
|
|
46
|
+
external?: string[];
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Browser view build configurations
|
|
51
|
+
*/
|
|
52
|
+
views?: {
|
|
53
|
+
[viewName: string]: {
|
|
54
|
+
/**
|
|
55
|
+
* Entry point for this view's TypeScript code
|
|
56
|
+
*/
|
|
57
|
+
entrypoint: string;
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* External modules to exclude from bundling for this view
|
|
61
|
+
*/
|
|
62
|
+
external?: string[];
|
|
63
|
+
};
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Files to copy directly to the build output
|
|
68
|
+
* Key is source path, value is destination path
|
|
69
|
+
*/
|
|
70
|
+
copy?: {
|
|
71
|
+
[sourcePath: string]: string;
|
|
72
|
+
};
|
|
73
|
+
/**
|
|
74
|
+
* Output folder for built application
|
|
75
|
+
* @default "build"
|
|
76
|
+
*/
|
|
77
|
+
buildFolder?: string;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Output folder for distribution artifacts
|
|
81
|
+
* @default "artifacts"
|
|
82
|
+
*/
|
|
83
|
+
artifactFolder?: string;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Build targets to compile for
|
|
87
|
+
* Can be "current", "all", or comma-separated list like "macos-arm64,win-x64"
|
|
88
|
+
*/
|
|
89
|
+
targets?: string;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* macOS-specific build configuration
|
|
93
|
+
*/
|
|
94
|
+
mac?: {
|
|
95
|
+
/**
|
|
96
|
+
* Enable code signing for macOS builds
|
|
97
|
+
* @default false
|
|
98
|
+
*/
|
|
99
|
+
codesign?: boolean;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Enable notarization for macOS builds (requires codesign)
|
|
103
|
+
* @default false
|
|
104
|
+
*/
|
|
105
|
+
notarize?: boolean;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Bundle CEF (Chromium Embedded Framework) instead of using system WebView
|
|
109
|
+
* @default false
|
|
110
|
+
*/
|
|
111
|
+
bundleCEF?: boolean;
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* macOS entitlements for code signing
|
|
115
|
+
*/
|
|
116
|
+
entitlements?: Record<string, boolean | string>;
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Path to .iconset folder containing app icons
|
|
120
|
+
* @default "icon.iconset"
|
|
121
|
+
*/
|
|
122
|
+
icons?: string;
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Windows-specific build configuration
|
|
127
|
+
*/
|
|
128
|
+
win?: {
|
|
129
|
+
/**
|
|
130
|
+
* Bundle CEF (Chromium Embedded Framework) instead of using WebView2
|
|
131
|
+
* @default false
|
|
132
|
+
*/
|
|
133
|
+
bundleCEF?: boolean;
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Linux-specific build configuration
|
|
138
|
+
*/
|
|
139
|
+
linux?: {
|
|
140
|
+
/**
|
|
141
|
+
* Bundle CEF (Chromium Embedded Framework) instead of using GTKWebKit
|
|
142
|
+
* Recommended on Linux for advanced layer compositing features
|
|
143
|
+
* @default false
|
|
144
|
+
*/
|
|
145
|
+
bundleCEF?: boolean;
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Build scripts configuration
|
|
151
|
+
*/
|
|
152
|
+
scripts?: {
|
|
153
|
+
/**
|
|
154
|
+
* Script to run after build completes
|
|
155
|
+
* Can be a path to a script file
|
|
156
|
+
*/
|
|
157
|
+
postBuild?: string;
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Release and distribution configuration
|
|
162
|
+
*/
|
|
163
|
+
release?: {
|
|
164
|
+
/**
|
|
165
|
+
* Base URL for artifact distribution (e.g., S3 bucket URL)
|
|
166
|
+
* Used for auto-updates and patch generation
|
|
167
|
+
*/
|
|
168
|
+
bucketUrl?: string;
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
@@ -182,6 +182,10 @@ export class BrowserWindow<T> {
|
|
|
182
182
|
return ffi.request.closeWindow({ winId: this.id });
|
|
183
183
|
}
|
|
184
184
|
|
|
185
|
+
focus() {
|
|
186
|
+
return ffi.request.focusWindow({ winId: this.id });
|
|
187
|
+
}
|
|
188
|
+
|
|
185
189
|
// todo (yoav): move this to a class that also has off, append, prepend, etc.
|
|
186
190
|
// name should only allow browserWindow events
|
|
187
191
|
on(name, handler) {
|
|
@@ -73,6 +73,13 @@ export class Tray {
|
|
|
73
73
|
electrobunEventEmitter.on(specificName, handler);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
remove() {
|
|
77
|
+
console.log('Tray.remove() called for id:', this.id);
|
|
78
|
+
ffi.request.removeTray({ id: this.id });
|
|
79
|
+
delete TrayMap[this.id];
|
|
80
|
+
console.log('Tray removed from TrayMap');
|
|
81
|
+
}
|
|
82
|
+
|
|
76
83
|
static getById(id: number) {
|
|
77
84
|
return TrayMap[id];
|
|
78
85
|
}
|
|
@@ -80,6 +87,13 @@ export class Tray {
|
|
|
80
87
|
static getAll() {
|
|
81
88
|
return Object.values(TrayMap);
|
|
82
89
|
}
|
|
90
|
+
|
|
91
|
+
static removeById(id: number) {
|
|
92
|
+
const tray = TrayMap[id];
|
|
93
|
+
if (tray) {
|
|
94
|
+
tray.remove();
|
|
95
|
+
}
|
|
96
|
+
}
|
|
83
97
|
}
|
|
84
98
|
|
|
85
99
|
const menuConfigWithDefaults = (
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { join, dirname, resolve, basename } from "path";
|
|
1
|
+
import { join, dirname, resolve, basename, relative } from "path";
|
|
2
2
|
import { homedir } from "os";
|
|
3
3
|
import { renameSync, unlinkSync, mkdirSync, rmdirSync, statSync, readdirSync, cpSync } from "fs";
|
|
4
4
|
import { execSync } from "child_process";
|
|
@@ -379,9 +379,10 @@ const Updater = {
|
|
|
379
379
|
if (currentOS === 'win') {
|
|
380
380
|
console.log(`Using Windows native tar.exe to extract ${latestTarPath} to ${extractionDir}...`);
|
|
381
381
|
try {
|
|
382
|
-
|
|
382
|
+
const relativeTarPath = relative(extractionDir, latestTarPath);
|
|
383
|
+
execSync(`tar -xf "${relativeTarPath}"`, {
|
|
383
384
|
stdio: 'inherit',
|
|
384
|
-
cwd: extractionDir
|
|
385
|
+
cwd: extractionDir
|
|
385
386
|
});
|
|
386
387
|
console.log('Windows tar.exe extraction completed successfully');
|
|
387
388
|
|
package/dist/api/bun/index.ts
CHANGED
|
@@ -10,11 +10,13 @@ import { type RPCSchema, createRPC } from "rpc-anywhere";
|
|
|
10
10
|
import type ElectrobunEvent from "./events/event";
|
|
11
11
|
import * as PATHS from "./core/Paths";
|
|
12
12
|
import * as Socket from "./core/Socket";
|
|
13
|
+
import type { ElectrobunConfig } from "./ElectrobunConfig";
|
|
13
14
|
|
|
14
15
|
// Named Exports
|
|
15
16
|
export {
|
|
16
17
|
type RPCSchema,
|
|
17
18
|
type ElectrobunEvent,
|
|
19
|
+
type ElectrobunConfig,
|
|
18
20
|
createRPC,
|
|
19
21
|
BrowserWindow,
|
|
20
22
|
BrowserView,
|
|
@@ -49,6 +49,12 @@ export const native = (() => {
|
|
|
49
49
|
],
|
|
50
50
|
returns: FFIType.void,
|
|
51
51
|
},
|
|
52
|
+
closeNSWindow: {
|
|
53
|
+
args: [
|
|
54
|
+
FFIType.ptr, // window ptr
|
|
55
|
+
],
|
|
56
|
+
returns: FFIType.void,
|
|
57
|
+
},
|
|
52
58
|
// webview
|
|
53
59
|
initWebview: {
|
|
54
60
|
args: [
|
|
@@ -180,6 +186,10 @@ export const native = (() => {
|
|
|
180
186
|
args: [FFIType.ptr, FFIType.cstring],
|
|
181
187
|
returns: FFIType.void
|
|
182
188
|
},
|
|
189
|
+
removeTray: {
|
|
190
|
+
args: [FFIType.ptr],
|
|
191
|
+
returns: FFIType.void
|
|
192
|
+
},
|
|
183
193
|
setApplicationMenu: {
|
|
184
194
|
args: [FFIType.cstring, FFIType.function],
|
|
185
195
|
returns: FFIType.void
|
|
@@ -345,7 +355,10 @@ export const ffi = {
|
|
|
345
355
|
}
|
|
346
356
|
|
|
347
357
|
native.symbols.setNSWindowTitle(windowPtr, toCString(title));
|
|
358
|
+
// setTimeout(() => {
|
|
359
|
+
// console.log('calling makeNSWindowKeyAndOrderFront', windowPtr)
|
|
348
360
|
native.symbols.makeNSWindowKeyAndOrderFront(windowPtr);
|
|
361
|
+
// }, 1000)
|
|
349
362
|
|
|
350
363
|
return windowPtr;
|
|
351
364
|
},
|
|
@@ -360,6 +373,29 @@ export const ffi = {
|
|
|
360
373
|
|
|
361
374
|
native.symbols.setNSWindowTitle(windowPtr, toCString(title));
|
|
362
375
|
},
|
|
376
|
+
|
|
377
|
+
closeWindow: (params: {winId: number}) => {
|
|
378
|
+
const {winId} = params;
|
|
379
|
+
const windowPtr = BrowserWindow.getById(winId)?.ptr;
|
|
380
|
+
|
|
381
|
+
if (!windowPtr) {
|
|
382
|
+
throw `Can't close window. Window no longer exists`;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
native.symbols.closeNSWindow(windowPtr);
|
|
386
|
+
// Note: Cleanup of BrowserWindowMap happens in the windowCloseCallback
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
focusWindow: (params: {winId: number}) => {
|
|
390
|
+
const {winId} = params;
|
|
391
|
+
const windowPtr = BrowserWindow.getById(winId)?.ptr;
|
|
392
|
+
|
|
393
|
+
if (!windowPtr) {
|
|
394
|
+
throw `Can't focus window. Window no longer exists`;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
native.symbols.makeNSWindowKeyAndOrderFront(windowPtr);
|
|
398
|
+
},
|
|
363
399
|
|
|
364
400
|
createWebview: (params: {
|
|
365
401
|
id: number;
|
|
@@ -653,6 +689,22 @@ export const ffi = {
|
|
|
653
689
|
toCString(menuConfig)
|
|
654
690
|
);
|
|
655
691
|
},
|
|
692
|
+
|
|
693
|
+
removeTray: (params: { id: number }): void => {
|
|
694
|
+
const { id } = params;
|
|
695
|
+
console.log('removeTray called with id:', id);
|
|
696
|
+
const tray = Tray.getById(id);
|
|
697
|
+
console.log('Found tray:', tray);
|
|
698
|
+
|
|
699
|
+
if (!tray) {
|
|
700
|
+
throw `Can't remove tray. Tray no longer exists`;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
console.log('Calling native.symbols.removeTray with ptr:', tray.ptr);
|
|
704
|
+
native.symbols.removeTray(tray.ptr);
|
|
705
|
+
console.log('Native removeTray called successfully');
|
|
706
|
+
// The Tray class will handle removing from TrayMap
|
|
707
|
+
},
|
|
656
708
|
setApplicationMenu: (params: {menuConfig: string}): void => {
|
|
657
709
|
const {
|
|
658
710
|
menuConfig
|
|
@@ -725,6 +777,16 @@ process.on('unhandledRejection', (reason, promise) => {
|
|
|
725
777
|
console.error('Unhandled rejection in worker:', reason);
|
|
726
778
|
});
|
|
727
779
|
|
|
780
|
+
process.on('SIGINT', () => {
|
|
781
|
+
console.log('[electrobun] Received SIGINT, calling killApp() for graceful shutdown...');
|
|
782
|
+
native.symbols.killApp();
|
|
783
|
+
});
|
|
784
|
+
|
|
785
|
+
process.on('SIGTERM', () => {
|
|
786
|
+
console.log('[electrobun] Received SIGTERM, calling killApp() for graceful shutdown...');
|
|
787
|
+
native.symbols.killApp();
|
|
788
|
+
});
|
|
789
|
+
|
|
728
790
|
|
|
729
791
|
|
|
730
792
|
|
|
@@ -1110,6 +1172,7 @@ export const internalRpcHandlers = {
|
|
|
1110
1172
|
},
|
|
1111
1173
|
webviewTagCallAsyncJavaScript: (params) => {
|
|
1112
1174
|
console.log('-----------+ request: ', 'webviewTagCallAsyncJavaScript', params)
|
|
1175
|
+
// Not implemented - users can use RPC for JavaScript execution if needed
|
|
1113
1176
|
}
|
|
1114
1177
|
},
|
|
1115
1178
|
message: {
|
|
@@ -1126,33 +1189,60 @@ export const internalRpcHandlers = {
|
|
|
1126
1189
|
native.symbols.resizeWebview(webviewPtr, x, y, width, height, toCString(params.masks))
|
|
1127
1190
|
},
|
|
1128
1191
|
webviewTagUpdateSrc: (params) => {
|
|
1129
|
-
const
|
|
1130
|
-
|
|
1192
|
+
const webview = BrowserView.getById(params.id);
|
|
1193
|
+
if (!webview || !webview.ptr) {
|
|
1194
|
+
console.error(`webviewTagUpdateSrc: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1195
|
+
return;
|
|
1196
|
+
}
|
|
1197
|
+
native.symbols.loadURLInWebView(webview.ptr, toCString(params.url));
|
|
1131
1198
|
},
|
|
1132
1199
|
webviewTagUpdateHtml: (params) => {
|
|
1133
|
-
const webview = BrowserView.getById(params.id);
|
|
1134
|
-
webview.
|
|
1200
|
+
const webview = BrowserView.getById(params.id);
|
|
1201
|
+
if (!webview || !webview.ptr) {
|
|
1202
|
+
console.error(`webviewTagUpdateHtml: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1203
|
+
return;
|
|
1204
|
+
}
|
|
1205
|
+
webview.loadHTML(params.html);
|
|
1135
1206
|
webview.html = params.html;
|
|
1136
|
-
|
|
1137
1207
|
},
|
|
1138
1208
|
webviewTagUpdatePreload: (params) => {
|
|
1139
1209
|
const webview = BrowserView.getById(params.id);
|
|
1210
|
+
if (!webview || !webview.ptr) {
|
|
1211
|
+
console.error(`webviewTagUpdatePreload: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1212
|
+
return;
|
|
1213
|
+
}
|
|
1140
1214
|
native.symbols.updatePreloadScriptToWebView(webview.ptr, toCString('electrobun_custom_preload_script'), toCString(params.preload), true);
|
|
1141
1215
|
},
|
|
1142
1216
|
webviewTagGoBack: (params) => {
|
|
1143
1217
|
const webview = BrowserView.getById(params.id);
|
|
1218
|
+
if (!webview || !webview.ptr) {
|
|
1219
|
+
console.error(`webviewTagGoBack: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1220
|
+
return;
|
|
1221
|
+
}
|
|
1144
1222
|
native.symbols.webviewGoBack(webview.ptr);
|
|
1145
1223
|
},
|
|
1146
1224
|
webviewTagGoForward: (params) => {
|
|
1147
1225
|
const webview = BrowserView.getById(params.id);
|
|
1226
|
+
if (!webview || !webview.ptr) {
|
|
1227
|
+
console.error(`webviewTagGoForward: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1228
|
+
return;
|
|
1229
|
+
}
|
|
1148
1230
|
native.symbols.webviewGoForward(webview.ptr);
|
|
1149
1231
|
},
|
|
1150
1232
|
webviewTagReload: (params) => {
|
|
1151
1233
|
const webview = BrowserView.getById(params.id);
|
|
1234
|
+
if (!webview || !webview.ptr) {
|
|
1235
|
+
console.error(`webviewTagReload: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1236
|
+
return;
|
|
1237
|
+
}
|
|
1152
1238
|
native.symbols.webviewReload(webview.ptr);
|
|
1153
1239
|
},
|
|
1154
1240
|
webviewTagRemove: (params) => {
|
|
1155
1241
|
const webview = BrowserView.getById(params.id);
|
|
1242
|
+
if (!webview || !webview.ptr) {
|
|
1243
|
+
console.error(`webviewTagRemove: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1244
|
+
return;
|
|
1245
|
+
}
|
|
1156
1246
|
native.symbols.webviewRemove(webview.ptr);
|
|
1157
1247
|
},
|
|
1158
1248
|
startWindowMove: (params) => {
|
|
@@ -1164,14 +1254,26 @@ export const internalRpcHandlers = {
|
|
|
1164
1254
|
},
|
|
1165
1255
|
webviewTagSetTransparent: (params) => {
|
|
1166
1256
|
const webview = BrowserView.getById(params.id);
|
|
1257
|
+
if (!webview || !webview.ptr) {
|
|
1258
|
+
console.error(`webviewTagSetTransparent: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1259
|
+
return;
|
|
1260
|
+
}
|
|
1167
1261
|
native.symbols.webviewSetTransparent(webview.ptr, params.transparent);
|
|
1168
1262
|
},
|
|
1169
1263
|
webviewTagSetPassthrough: (params) => {
|
|
1170
1264
|
const webview = BrowserView.getById(params.id);
|
|
1265
|
+
if (!webview || !webview.ptr) {
|
|
1266
|
+
console.error(`webviewTagSetPassthrough: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1267
|
+
return;
|
|
1268
|
+
}
|
|
1171
1269
|
native.symbols.webviewSetPassthrough(webview.ptr, params.enablePassthrough);
|
|
1172
1270
|
},
|
|
1173
1271
|
webviewTagSetHidden: (params) => {
|
|
1174
1272
|
const webview = BrowserView.getById(params.id);
|
|
1273
|
+
if (!webview || !webview.ptr) {
|
|
1274
|
+
console.error(`webviewTagSetHidden: BrowserView not found or has no ptr for id ${params.id}`);
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1175
1277
|
native.symbols.webviewSetHidden(webview.ptr, params.hidden);
|
|
1176
1278
|
},
|
|
1177
1279
|
webviewEvent: (params) => {
|
package/dist/main.js
CHANGED
|
@@ -5,11 +5,12 @@ var __require = import.meta.require;
|
|
|
5
5
|
import { join, dirname, resolve } from "path";
|
|
6
6
|
import { dlopen, suffix } from "bun:ffi";
|
|
7
7
|
import { existsSync } from "fs";
|
|
8
|
-
var
|
|
8
|
+
var pathToMacOS = dirname(process.argv0);
|
|
9
|
+
var libPath = join(pathToMacOS, `libNativeWrapper.${suffix}`);
|
|
9
10
|
var absoluteLibPath = resolve(libPath);
|
|
10
11
|
function main() {
|
|
11
12
|
if (process.platform === "linux") {
|
|
12
|
-
const cefLibs = ["
|
|
13
|
+
const cefLibs = [join(pathToMacOS, "libcef.so"), join(pathToMacOS, "libvk_swiftshader.so")];
|
|
13
14
|
const existingCefLibs = cefLibs.filter((lib2) => existsSync(lib2));
|
|
14
15
|
if (existingCefLibs.length > 0 && !process.env.LD_PRELOAD) {
|
|
15
16
|
console.error(`[LAUNCHER] ERROR: CEF libraries found but LD_PRELOAD not set!`);
|
|
@@ -45,8 +46,8 @@ function main() {
|
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
48
|
const pathToLauncherBin = process.argv0;
|
|
48
|
-
const
|
|
49
|
-
const appEntrypointPath = join(
|
|
49
|
+
const pathToBinDir = dirname(pathToLauncherBin);
|
|
50
|
+
const appEntrypointPath = join(pathToBinDir, "..", "Resources", "app", "bun", "index.js");
|
|
50
51
|
new Worker(appEntrypointPath, {});
|
|
51
52
|
lib.symbols.runNSApplication();
|
|
52
53
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electrobun",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Build ultra fast, tiny, and cross-platform desktop apps with Typescript.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Blackboard Technologies Inc.",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"dev:playground:clean": "cd playground && rm -rf node_modules && npm install && cd .. && bun dev:playground",
|
|
37
37
|
"dev:playground:rerun": "cd playground && bun start",
|
|
38
38
|
"dev:playground:canary": "bun build:release && cd playground && npm install && bun build:canary && bun start:canary",
|
|
39
|
+
"run:playground": "bun build:dev && bun build:cli && cd templates/interactive-playground && npm install && bun build:dev && bun start",
|
|
39
40
|
"dev:docs": "cd documentation && bun start",
|
|
40
41
|
"build:docs:release": "cd documentation && bun run build",
|
|
41
42
|
"npm:publish": "bun build:release && npm publish",
|
|
@@ -45,7 +46,8 @@
|
|
|
45
46
|
"push:patch": "npm version patch && git push origin main --tags",
|
|
46
47
|
"push:minor": "npm version minor && git push origin main --tags",
|
|
47
48
|
"push:major": "npm version major && git push origin main --tags",
|
|
48
|
-
"build:push:artifacts": "bun scripts/build-and-upload-artifacts.js"
|
|
49
|
+
"build:push:artifacts": "bun scripts/build-and-upload-artifacts.js",
|
|
50
|
+
"test": "bun build:dev && bun build:cli && cd tests && npm install && bun build:dev && bun start"
|
|
49
51
|
},
|
|
50
52
|
"devDependencies": {
|
|
51
53
|
"@types/archiver": "^6.0.3",
|