electrobun 0.0.19-beta.99 → 0.1.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.
Files changed (77) hide show
  1. package/README.md +1 -1
  2. package/dist/api/browser/webviewtag.ts +54 -2
  3. package/dist/api/bun/ElectrobunConfig.ts +171 -0
  4. package/dist/api/bun/core/BrowserWindow.ts +4 -0
  5. package/dist/api/bun/core/Tray.ts +14 -0
  6. package/dist/api/bun/core/Updater.ts +4 -3
  7. package/dist/api/bun/index.ts +2 -0
  8. package/dist/api/bun/proc/native.ts +107 -5
  9. package/dist/main.js +5 -4
  10. package/package.json +4 -2
  11. package/src/cli/index.ts +565 -148
  12. package/templates/hello-world/bun.lock +164 -2
  13. package/templates/hello-world/electrobun.config.ts +28 -0
  14. package/templates/hello-world/src/bun/index.ts +2 -2
  15. package/templates/hello-world/src/mainview/index.html +5 -6
  16. package/templates/hello-world/src/mainview/index.ts +1 -5
  17. package/templates/interactive-playground/README.md +26 -0
  18. package/templates/interactive-playground/assets/tray-icon.png +0 -0
  19. package/templates/interactive-playground/electrobun.config.ts +36 -0
  20. package/templates/interactive-playground/package-lock.json +36 -0
  21. package/templates/interactive-playground/package.json +15 -0
  22. package/templates/interactive-playground/src/bun/demos/files.ts +70 -0
  23. package/templates/interactive-playground/src/bun/demos/menus.ts +139 -0
  24. package/templates/interactive-playground/src/bun/demos/rpc.ts +83 -0
  25. package/templates/interactive-playground/src/bun/demos/system.ts +72 -0
  26. package/templates/interactive-playground/src/bun/demos/updates.ts +105 -0
  27. package/templates/interactive-playground/src/bun/demos/windows.ts +90 -0
  28. package/templates/interactive-playground/src/bun/index.ts +124 -0
  29. package/templates/interactive-playground/src/bun/types/rpc.ts +109 -0
  30. package/templates/interactive-playground/src/mainview/components/EventLog.ts +107 -0
  31. package/templates/interactive-playground/src/mainview/components/Sidebar.ts +65 -0
  32. package/templates/interactive-playground/src/mainview/components/Toast.ts +57 -0
  33. package/templates/interactive-playground/src/mainview/demos/FileDemo.ts +211 -0
  34. package/templates/interactive-playground/src/mainview/demos/MenuDemo.ts +102 -0
  35. package/templates/interactive-playground/src/mainview/demos/RPCDemo.ts +229 -0
  36. package/templates/interactive-playground/src/mainview/demos/TrayDemo.ts +132 -0
  37. package/templates/interactive-playground/src/mainview/demos/WebViewDemo.ts +411 -0
  38. package/templates/interactive-playground/src/mainview/demos/WindowDemo.ts +207 -0
  39. package/templates/interactive-playground/src/mainview/index.css +538 -0
  40. package/templates/interactive-playground/src/mainview/index.html +103 -0
  41. package/templates/interactive-playground/src/mainview/index.ts +238 -0
  42. package/templates/multitab-browser/README.md +34 -0
  43. package/templates/multitab-browser/bun.lock +224 -0
  44. package/templates/multitab-browser/electrobun.config.ts +32 -0
  45. package/templates/multitab-browser/package-lock.json +20 -0
  46. package/templates/multitab-browser/package.json +12 -0
  47. package/templates/multitab-browser/src/bun/index.ts +144 -0
  48. package/templates/multitab-browser/src/bun/tabManager.ts +200 -0
  49. package/templates/multitab-browser/src/bun/types/rpc.ts +78 -0
  50. package/templates/multitab-browser/src/mainview/index.css +487 -0
  51. package/templates/multitab-browser/src/mainview/index.html +94 -0
  52. package/templates/multitab-browser/src/mainview/index.ts +634 -0
  53. package/templates/photo-booth/README.md +108 -0
  54. package/templates/photo-booth/bun.lock +239 -0
  55. package/templates/photo-booth/electrobun.config.ts +28 -0
  56. package/templates/photo-booth/package.json +16 -0
  57. package/templates/photo-booth/src/bun/index.ts +92 -0
  58. package/templates/photo-booth/src/mainview/index.css +465 -0
  59. package/templates/photo-booth/src/mainview/index.html +124 -0
  60. package/templates/photo-booth/src/mainview/index.ts +499 -0
  61. package/tests/bun.lock +14 -0
  62. package/tests/electrobun.config.ts +45 -0
  63. package/tests/package-lock.json +36 -0
  64. package/tests/package.json +13 -0
  65. package/tests/src/bun/index.ts +100 -0
  66. package/tests/src/bun/test-runner.ts +508 -0
  67. package/tests/src/mainview/index.html +110 -0
  68. package/tests/src/mainview/index.ts +458 -0
  69. package/tests/src/mainview/styles/main.css +451 -0
  70. package/tests/src/testviews/tray-test.html +57 -0
  71. package/tests/src/testviews/webview-mask.html +114 -0
  72. package/tests/src/testviews/webview-navigation.html +36 -0
  73. package/tests/src/testviews/window-create.html +17 -0
  74. package/tests/src/testviews/window-events.html +29 -0
  75. package/tests/src/testviews/window-focus.html +37 -0
  76. package/tests/src/webviewtag/index.ts +11 -0
  77. 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 4KB (using bsdiff it only downloads tiny patches between versions)
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
- this.internalRpc.send.webviewTagRemove({ id: this.webviewId });
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
- execSync(`tar -xf "${latestTarPath}" -C "${extractionDir}"`, {
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
 
@@ -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 webviewPtr = BrowserView.getById(params.id)?.ptr;
1130
- native.symbols.loadURLInWebView(webviewPtr, toCString(params.url))
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.loadHTML(params.html)
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 libPath = `./libNativeWrapper.${suffix}`;
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 = ["./libcef.so", "./libvk_swiftshader.so"];
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 pathToMacOS = dirname(pathToLauncherBin);
49
- const appEntrypointPath = join(pathToMacOS, "..", "Resources", "app", "bun", "index.js");
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.0.19-beta.99",
3
+ "version": "0.1.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.",
@@ -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",